Gibt es Bibliotheken für In-Browser-Javascript, die die gleiche Flexibilität / Modularität / Benutzerfreundlichkeit bieten wie die von Node require
?
Um mehr Details zu liefern: Der Grund require
ist so gut, dass es:
- Ermöglicht das dynamische Laden von Code von anderen Speicherorten (was meiner Meinung nach stilistisch besser ist, als den gesamten Code im HTML zu verknüpfen).
- Es bietet eine konsistente Schnittstelle zum Erstellen von Modulen
- Es ist für Module einfach, von anderen Modulen abhängig zu sein (so könnte ich beispielsweise eine API schreiben, für die jQuery erforderlich ist, damit ich sie verwenden kann
jQuery.ajax()
- Geladenes Javascript hat einen Gültigkeitsbereich , was bedeutet , dass ich es laden
var dsp = require("dsp.js");
und darauf zugreifen kanndsp.FFT
, was meine lokale Umgebung nicht beeinträchtigen würdevar FFT
Ich habe noch keine Bibliothek gefunden, die dies effektiv erledigt. Die Problemumgehungen, die ich normalerweise verwende, sind:
coffeescript-concat - es ist einfach genug, andere js zu benötigen, aber Sie müssen es kompilieren, was bedeutet, dass es für eine schnelle Entwicklung weniger geeignet ist (z. B. Erstellen von APIs im Test)
RequireJS - Es ist beliebt, unkompliziert und löst 1-3, aber mangelndes Scoping ist ein echter Deal-Breaker (ich glaube, head.js ist insofern ähnlich, als es kein Scoping gibt, obwohl ich nie Gelegenheit hatte, es zu verwenden. In ähnlicher Weise können LABjs
.wait()
Abhängigkeitsprobleme laden und besänftigen , aber es wird immer noch kein Scoping durchgeführt.
Soweit ich das beurteilen kann, scheint es viele Lösungen für das dynamische und / oder asynchrone Laden von Javascript zu geben, aber sie haben tendenziell die gleichen Probleme wie das Laden der Js aus HTML. Vor allem möchte ich eine Möglichkeit zum Laden von Javascript, die den globalen Namespace überhaupt nicht verschmutzt, mir aber dennoch das Laden und Verwenden von Bibliotheken ermöglicht (genau wie es der Knoten erfordert).
2020 UPDATE: Module sind jetzt Standard in ES6 und werden ab Mitte 2020 von den meisten Browsern nativ unterstützt . Module unterstützen sowohl das synchrone als auch das asynchrone Laden (mit Promise). Meine aktuelle Empfehlung lautet, dass die meisten neuen Projekte ES6-Module verwenden und einen Transpiler verwenden sollten, um für ältere Browser auf eine einzelne JS-Datei zurückzugreifen.
Generell ist die Bandbreite heute auch viel größer als damals, als ich diese Frage gestellt habe. In der Praxis könnten Sie sich also vernünftigerweise dafür entscheiden, immer einen Transpiler mit ES6-Modulen zu verwenden und sich eher auf die Code-Effizienz als auf das Netzwerk zu konzentrieren.
VORHERIGE BEARBEITUNG (oder wenn Sie ES6-Module nicht mögen): Seit dem Schreiben habe ich RequireJS (das jetzt eine viel klarere Dokumentation enthält) ausgiebig verwendet . RequireJS war meiner Meinung nach wirklich die richtige Wahl. Ich möchte klarstellen, wie das System für Menschen funktioniert, die genauso verwirrt sind wie ich:
Sie können require
in der täglichen Entwicklung verwenden. Ein Modul kann alles sein, was von einer Funktion zurückgegeben wird (normalerweise ein Objekt oder eine Funktion) und wird als Parameter festgelegt. Sie können Ihr Projekt auch zur Bereitstellung in eine einzige Datei kompilieren r.js
(in der Praxis ist dies fast immer schneller, obwohl require
Skripte parallel geladen werden können).
Der Hauptunterschied zwischen RequireJS und Node-Style-Anforderungen wie browserify (ein cooles Projekt, das von tjameson vorgeschlagen wird) besteht in der Art und Weise, wie Module entworfen und benötigt werden:
- RequireJS verwendet AMD (Async Module Definition). In AMD werden
require
eine Liste der zu ladenden Module (Javascript-Dateien) und eine Rückruffunktion verwendet. Wenn jedes der Module geladen wurde, ruft es den Rückruf mit jedem Modul als Parameter für den Rückruf auf. Somit ist es wirklich asynchron und daher gut für das Web geeignet. - Der Knoten verwendet CommonJS. In CommonJS
require
handelt es sich um einen blockierenden Aufruf, der ein Modul lädt und als Objekt zurückgibt. Dies funktioniert gut für Node, da Dateien aus dem Dateisystem gelesen werden, was schnell genug ist, aber im Web schlecht funktioniert, da das synchrone Laden von Dateien viel länger dauern kann.
In der Praxis haben viele Entwickler Node (und damit CommonJS) verwendet, bevor sie AMD jemals sehen. Darüber hinaus werden viele Bibliotheken / Module für CommonJS (durch Hinzufügen von Elementen zu einem exports
Objekt) und nicht für AMD (durch Zurückgeben des Moduls von der define
Funktion) geschrieben. Daher möchten viele Node-Turned-Web-Entwickler CommonJS-Bibliotheken im Web verwenden. Dies ist möglich, da das Laden von einem <script>
Tag blockiert. Lösungen wie browserify verwenden CommonJS (Node) -Module und schließen sie zusammen, damit Sie sie in Skript-Tags einfügen können.
Wenn Sie Ihr eigenes Projekt mit mehreren Dateien für das Web entwickeln, empfehle ich RequireJS dringend, da es sich wirklich um ein Modulsystem für das Web handelt (obwohl ich AMD bei fairer Offenlegung viel natürlicher finde als CommonJS). In letzter Zeit hat die Unterscheidung an Bedeutung verloren, da Sie mit RequireJS jetzt im Wesentlichen die CommonJS-Syntax verwenden können. Zusätzlich kann RequireJS verwendet werden, um AMD-Module in Node zu laden (obwohl ich Node-Amd-Loader bevorzuge ).
quelle
Antworten:
Schauen Sie sich ender an . Es macht viel davon.
Auch browserify ist ziemlich gut. Ich habe Require-Kiss ¹ verwendet und es funktioniert. Es gibt wahrscheinlich andere.
Ich bin mir bei RequireJS nicht sicher. Es ist einfach nicht dasselbe wie bei Node. Möglicherweise treten Probleme beim Laden von anderen Speicherorten auf, dies funktioniert jedoch möglicherweise. Solange es eine Bereitstellungsmethode gibt oder etwas, das aufgerufen werden kann.
TL; DR - Ich würde browserify oder require-kiss empfehlen.
Aktualisieren:
1: require-kiss ist jetzt tot und der Autor hat es entfernt. Ich benutze RequireJS seitdem ohne Probleme. Der Autor von require-kiss schrieb pakmanager und pakman . Vollständige Offenlegung, ich arbeite mit dem Entwickler.
Persönlich mag ich RequireJS besser. Das Debuggen ist viel einfacher (Sie können separate Dateien in der Entwicklung und eine einzelne bereitgestellte Datei in der Produktion haben) und basiert auf einem soliden "Standard".
quelle
Ich habe ein kleines Skript geschrieben, das das asynchrone und synchrone Laden von Javascript-Dateien ermöglicht, was hier von Nutzen sein könnte. Es hat keine Abhängigkeiten und ist kompatibel mit Node.js & CommonJS. Die Installation ist ziemlich einfach:
$ npm install --save @tarp/require
Fügen Sie dann einfach die folgenden Zeilen zu Ihrem HTML hinzu, um das Hauptmodul zu laden:
<script src="/node_modules/@tarp/require/require.min.js"></script> <script>Tarp.require({main: "./scripts/main"});</script>
In Ihrem Hauptmodul (und natürlich in jedem Untermodul) können Sie es so verwenden,
require()
wie Sie es von CommonJS / NodeJS kennen. Die vollständigen Dokumente und den Code finden Sie auf GitHub .quelle
Eine Variation der großartigen Antwort von Ilya Kharlamov mit etwas Code, damit es mit Chrome-Entwicklertools gut funktioniert.
// ///- 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
quelle
Mir ist klar, dass es Anfänger geben kann, die ihren Code organisieren möchten. Dies ist 2020 , und wenn Sie eine modulare JS-App in Betracht ziehen, sollten Sie sofort mit npm und Webpack beginnen .
Hier sind ein paar einfache Schritte, um loszulegen:
npm init -y
in Ihrem Projektstamm aus, um ein npm-Projekt zu initialisierennpm install webpack webpack-cli
_bundle.js
Achten Sie besonders auf die Datei - dies ist eine endgültige JS-Datei, die vom Webpack generiert wird. Sie werden sie nicht direkt ändern (lesen Sie weiter).<project-root>/app.js
in das Sie andere Module importieren:const printHello = require('./print-hello'); printHello();
print-hello.js
:module.exports = function() { console.log('Hello World!'); }
<project-root>/webpack.config.js
und kopieren Sie Folgendes:var path = require('path'); module.exports = { entry: './app.js', output: { path: path.resolve(__dirname), filename: '_bundle.js' } };
Im obigen Code gibt es 2 Punkte:
app.js
schreiben Sie Ihren JS-Code. Es werden andere Module wie oben gezeigt importiert._bundle.js
ist Ihr endgültiges Bundle, das vom Webpack generiert wird. Dies ist, was Ihr HTML am Ende sehen wird.-7. Öffnen Sie Ihre
package.js
und ersetzen Sie siescripts
durch den folgenden Befehl:"scripts": { "start": "webpack --mode production -w" },
app.js
und generieren Sie die_bundle.js
Datei, indem Sie Folgendes ausführen :npm start
.quelle
(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]; } })();
Wegen der Blockierung besser nicht in der Produktion verwenden. (In node.js ist require () ein blockierender Aufruf gut).
quelle
Webmake bündelt Node- ähnliche Module für den Browser. Probieren Sie es aus.
quelle
Require-Stub - Bietet knotenkonform
require
im Browser, löst sowohl Module als auch relative Pfade auf. Verwendet eine ähnliche Technik wie TKRequire (XMLHttpRequest). Der resultierende Code ist vollständig browserfähig undrequire-stub
kann als Ersatz für dienenwatchify
.quelle
Hier ist eine Erweiterung der fantastischen Antwort von Lucio M. Tato, die das rekursive Laden von Modulen mit relativen Pfaden ermöglicht.
Hier ist ein Github-Projekt, in dem die Lösung untergebracht ist, und ein Beispiel für deren Verwendung:
https://github.com/trausti/TKRequire.js
Fügen Sie zur Verwendung von TKRequire.js die folgende Zeile in Ihre Kopfzeile ein
Laden Sie dann Module wie in node.js:
quelle