ブラウザ内のJavaScriptにはノードスタイルが必要ですか?


83

ノードと同じ柔軟性/モジュール性/使いやすさを提供するブラウザ内JavaScript用のライブラリはありますrequireか?

詳細を提供するために:理由requireはとても良いですそれはそれです:

  1. コードを他の場所から動的にロードできるようにします(これは、すべてのコードをHTMLでリンクするよりも、スタイル的に優れていると思います)。
  2. モジュールを構築するための一貫したインターフェースを提供します
  3. モジュールが他のモジュールに依存するのは簡単です(たとえば、jQueryを必要とするAPIを記述して、使用できるようにすることができます) jQuery.ajax()
  4. ロードされたJavaScriptはスコープが設定されています。つまり、ロードしvar dsp = require("dsp.js");てアクセスできるためdsp.FFT、ローカルに干渉することはありません。var FFT

これを効果的に行うライブラリはまだ見つかりません。私がよく使用する回避策は次のとおりです。

  • coffeescript-concat-他のjsを必要とするのは簡単ですが、コンパイルする必要があります。つまり、高速開発(テスト中のAPIの構築など)にはあまり適していません。

  • RequireJS-人気があり、簡単で、1〜3を解決しますが、スコープの欠如は本当に大きな問題です(head.jsは、スコープがないという点で似ていると思いますが、使用する機会はありませんでした。同様に、LABjs.wait()依存関係の問題をロードして緩和できますが、それでもスコープは実行されません)

私の知る限り、JavaScriptの動的および/または非同期ロードには多くの解決策があるようですが、HTMLからjsをロードするのと同じスコープの問題が発生する傾向があります。何よりも、グローバル名前空間をまったく汚染しないが、ライブラリをロードして使用できるようにするJavaScriptをロードする方法が必要です(ノードの要求と同じように)。

2020年の更新: モジュールはES6で標準になり、2020年半ばの時点で、ほとんどのブラウザーでネイティブにサポートされています。モジュールは、同期と非同期(Promiseを使用)の両方のロードをサポートします。私の現在の推奨事項は、ほとんどの新しいプロジェクトでES6モジュールを使用し、トランスパイラーを使用してレガシーブラウザー用の単一のJSファイルにフォールバックすることです。

一般的な原則として、今日の帯域幅も通常、私が最初にこの質問をしたときよりもはるかに広くなっています。したがって、実際には、ES6モジュールで常にトランスパイラーを使用し、ネットワークではなくコード効率に注力することを合理的に選択する場合があります。

以前の編集(またはES6モジュールが気に入らない場合):これを書いた後、私はRequireJSを広範囲に使用しました(これにより、より明確なドキュメントが作成されました)。私の意見では、RequireJSは本当に正しい選択でした。私と同じように混乱している人々のためにシステムがどのように機能するかを明らかにしたいと思います。

require日常の開発にご利用いただけます。モジュールは、関数(通常はオブジェクトまたは関数)によって返されるものであれば何でもかまいません。スコープはパラメーターです。を使用してプロジェクトを単一のファイルにコンパイルしてデプロイすることもできますr.js(実際には、requireスクリプトを並行してロードできますが、これはほとんどの場合高速です)。

RequireJSとnode-stylerequireのようなbrowserify(tjamesonによって提案されたクールなプロジェクト)の使用の主な違いは、モジュールの設計方法と必要方法です。

  • RequireJSはAMD(非同期モジュール定義)を使用します。AMDでは、requireロードするモジュール(javascriptファイル)のリストとコールバック関数を取ります。各モジュールをロードすると、コールバックのパラメータとして各モジュールを使用してコールバックを呼び出します。したがって、これは真に非同期であるため、Webに最適です。
  • ノードはCommonJSを使用します。CommonJSではrequire、モジュールをロードしてオブジェクトとして返すブロッキング呼び出しです。これは、ファイルがファイルシステムから読み取られるため、ノードでは正常に機能します。これは十分に高速ですが、ファイルの同期ロードに時間がかかる可能性があるため、Webではうまく機能しません。

実際には、多くの開発者は、AMDを目にする前にNode(したがってCommonJS)を使用していました。さらに、多くのライブラリ/モジュールはexports、AMD(define関数からモジュールを返す)ではなく、CommonJS(オブジェクトに物を追加することによって)用に記述されています。したがって、ノード化されたWeb開発者の多くは、Web上でCommonJSライブラリを使用したいと考えています。<script>タグからの読み込みがブロックされているため、これが可能です。browserifyのようなソリューションは、CommonJS(Node)モジュールを取得してラップし、スクリプトタグで含めることができるようにします。

したがって、Web用に独自のマルチファイルプロジェクトを開発している場合は、RequireJSを強くお勧めします。これは本当にWeb用のモジュールシステムです(ただし、公正な開示では、AMDはCommonJSよりもはるかに自然です)。最近、RequireJSで基本的にCommonJS構文を使用できるようになったため、この区別はそれほど重要ではなくなりました。さらに、RequireJSを使用してノードにAMDモジュールをロードできます(ただし、node-amd-loaderの方が好きです)。


1
注RequireJSは実際にはモジュール性をサポートしており、スコープを設定できます。尋ねてから、私はそれをもう少し広範囲に使用しました。私の意見では、それは機能満載ですが、効果的に使用するには多くのドキュメントを読む必要があり、完璧になるには何らかの形のファーストクラスの同期ロードが必要です。
アレックスチャーチル

1
非同期であることの違いはそれほど意味がありますか?コードが必要なときはいつでも、関数を定義しているため、続行できないために基本的にブロックされています。そのため、何かを行う必要があります...
Michael

回答:


17

エンダーをチェックしてください。それはこれをたくさんします。

また、browserify はかなり良いです。require-kiss¹を使用しましたが、機能します。おそらく他にもあります。

RequireJSについてはよくわかりません。それはノードのものと同じではありません。他の場所からの読み込みで問題が発生する可能性がありますが、機能する可能性があります。呼び出すことができるprovideメソッドまたは何かがある限り。

TL; DR -browserifyまたはrequire-kissをお勧めします。


更新:

1:require-kissは無効になり、作成者は削除しました。それ以来、RequireJSを問題なく使用しています。require-kissの作者はpakmanagerpakmanを書きました。完全開示、私は開発者と協力しています。

個人的にはRequireJSの方が好きです。デバッグがはるかに簡単で(開発時に個別のファイルを作成し、本番環境に単一のデプロイ済みファイルを作成できます)、堅固な「標準」に基づいて構築されています。


かっこいい、まだbrowserifyを試していませんが、まさに私が必要としているように見えます。
アレックスチャーチル

require-kissへのリンクは死んでいるようです。単純な(再)検索はどこにもつながりませんでした-どこに行きましたか?
Joel Purra 2012

@ JoelPurra-require-kissは削除され、pakmanagerに置き換えられました。今すぐrequire-jsをお勧めします。答えを更新しました。
beatgammit 2012

ここでいい答えです:)、私が今やった質問をチェックしてみてください。これはこれに似ています(しかし同時に異なります)?stackoverflow.com/questions/43237875/...
Webeng

16

Javascriptファイルの非同期および同期ロードを可能にする小さなスクリプトを作成しました。これはここで役立つ可能性があります。依存関係はなく、Node.jsおよびCommonJSと互換性があります。インストールはとても簡単です:

$ npm install --save @tarp/require

次に、HTMLに次の行を追加して、メインモジュールをロードします。

<script src="/node_modules/@tarp/require/require.min.js"></script>
<script>Tarp.require({main: "./scripts/main"});</script>

メインモジュール(およびもちろんサブモジュール)内require()では、CommonJS / NodeJSから知っているとおりに使用できます。完全なドキュメントとコードはGitHubにあります


1
これは信じられないほどクールです。これを書いてくれてありがとう!
OldTimeGuitarGuy

ありがとう、@ OldTimeGuitarGuy :)
Torben

10

Ilya Kharlamovの素晴らしい答えのバリエーションで、Chrome開発者ツールでうまく機能するようにするためのコードがいくつかあります。

//
///- REQUIRE FN
// equivalent to require from node.js
function require(url){
    if (url.toLowerCase().substr(-3)!=='.js') url+='.js'; // to allow loading without js suffix;
    if (!require.cache) require.cache=[]; //init cache
    var exports=require.cache[url]; //get from cache
    if (!exports) { //not cached
            try {
                exports={};
                var X=new XMLHttpRequest();
                X.open("GET", url, 0); // sync
                X.send();
                if (X.status && X.status !== 200)  throw new Error(X.statusText);
                var source = X.responseText;
                // fix (if saved form for Chrome Dev Tools)
                if (source.substr(0,10)==="(function("){ 
                    var moduleStart = source.indexOf('{');
                    var moduleEnd = source.lastIndexOf('})');
                    var CDTcomment = source.indexOf('//@ ');
                    if (CDTcomment>-1 && CDTcomment<moduleStart+6) moduleStart = source.indexOf('\n',CDTcomment);
                    source = source.slice(moduleStart+1,moduleEnd-1); 
                } 
                // fix, add comment to show source on Chrome Dev Tools
                source="//@ sourceURL="+window.location.origin+url+"\n" + source;
                //------
                var module = { id: url, uri: url, exports:exports }; //according to node.js modules 
                var anonFn = new Function("require", "exports", "module", source); //create a Fn with module code, and 3 params: require, exports & module
                anonFn(require, exports, module); // call the Fn, Execute the module
                require.cache[url]  = exports = module.exports; //cache obj exported by module
            } catch (err) {
                throw new Error("Error loading module "+url+": "+err);
            }
    }
    return exports; //require returns object exported by module
}
///- END REQUIRE FN

ルシオありがとう!私は長い間、このような最小限の解決策を探していました。相対パスをサポートするように拡張しました。下記参照。
Trausti Kristjansson 2014年

8

コードを整理しようとしている初心者がいるかもしれません。これは2020年であり、モジュラーJSアプリを検討している場合は、今すぐnpmWebpackを使い始める必要があります。

開始するためのいくつかの簡単な手順は次のとおりです。

  1. プロジェクトルートでnpm init -y、npmプロジェクトを初期化するために実行します
  2. Webpackモジュールバンドラーをダウンロードします。 npm install webpack webpack-cli
  3. index.htmlファイルを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>App</title>
</head>
<body>

    <script src="_bundle.js"></script>
</body>
</html>

_bundle.jsファイルに特に注意してください-これはwebpackによって生成された最終的なJSファイルであり、直接変更することはありません(読み続けてください)。

  1. <project-root>/app.js他のモジュールをインポートするを作成します。
const printHello = require('./print-hello');

printHello();
  1. サンプルprint-hello.jsモジュールを作成します。
module.exports = function() {
    console.log('Hello World!');
}
  1. を作成し<project-root>/webpack.config.js、以下をコピーして貼り付けます。
var path = require('path');

module.exports = {
  entry: './app.js',
  output: {
    path: path.resolve(__dirname),
    filename: '_bundle.js'
  }
};

上記のコードには、2つのポイントがあります。

  • エントリapp.jsは、JSコードを記述する場所です。上記のように他のモジュールをインポートします。
  • 出力_bundle.jsは、webpackによって生成された最終的なバンドルです。これはあなたのhtmlが最後に見るものです。

-7。を開き、次のコマンドにpackage.js置き換えますscripts

  "scripts": {
    "start": "webpack --mode production -w"
  },
  1. 最後に、スクリプトウォッチapp.jsを実行し、次のコマンドを実行して_bundle.jsファイルを生成しますnpm start
  2. コーディングをお楽しみください!

1
2020年には、これを正解としてマークする必要があります
p13rnd

5
(function () {
    // c is cache, the rest are the constants
    var c = {},s="status",t="Text",e="exports",E="Error",r="require",m="module",S=" ",w=window;
    w[r]=function R(url) {
        url+=/.js$/i.test(url) ? "" : ".js";// to allow loading without js suffix;
        var X=new XMLHttpRequest(),module = { id: url, uri: url }; //according to the modules 1.1 standard
        if (!c[url])
            try {
                X.open("GET", url, 0); // sync
                X.send();
                if (X[s] && X[s] != 200) 
                    throw X[s+t];
                Function(r, e, m, X['response'+t])(R, c[url]={}, module); // Execute the module
                module[e] && (c[url]=module[e]);
            } catch (x) {
                throw w[E](E+" in "+r+": Can't load "+m+S+url+":"+S+x);
            }
        return c[url];
    }
})();

ブロッキングのため、本番環境では使用しない方がよいでしょう。(node.jsでは、require()はブロッキング呼び出しです)。


「モジュール」のプロパティである「exports:{}」であってはなりませんか?そして、呼び出しは(R、module.exports、module)
Lucio M. Tato

@ LucioM.Tatoわかりませんが、Modules1.1標準のmodule.exportsについての言及はありません。いつでもrequire(module.id)を呼び出して、エクスポートを取得できます
Ilya Kharlamov

はい。そうです、私はnode.jsモジュールの実装について考えていました。Chrome Dev Toolsでうまく動作するように、本当に良い答えのコードにいくつかの変更を加えました(デバッグ時のIDEとして使用しています)。他の誰かに役立つ場合に備えて、この質問に対する別の回答としてコードを投稿します。
Lucio M. Tato 2013年


1

Require-stubrequireブラウザでノード準拠を提供し、モジュールと相対パスの両方を解決します。TKRequire(XMLHttpRequest)と同様の技術を使用します。結果のコードは完全にブラウザ化require-stub可能であり、の代わりに使用できwatchifyます。


0

これは、相対パスを持つモジュールの再帰的なロードを可能にするLucio M.Tatoの素晴らしい答えの拡張です。

ソリューションとその使用方法の例を格納するgithubプロジェクトを次に示します。

https://github.com/trausti/TKRequire.js

TKRequire.jsを使用するには、ヘッダーに次の行を含めます

<script type = "text / javascript" src = "./ TKRequire.js"> </ script>

次に、node.jsと同じようにモジュールをロードします。

var MyModule = require( "./ related / path / to / MyModule.js");


Traustiに感謝します。javascriptを使用している場合は、github.com / luciotato / LiteScript(ベータ版)を確認する必要があります。PD:あなたは今どのレベルのCC佐賀をプレイしていますか?:P
Lucio M. Tato 2014年

リンクが切れています。どうすればコードを取得して確認できますか?
PA。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.