Czy są jakieś biblioteki dla javascript w przeglądarce, które zapewniają taką samą elastyczność / modułowość / łatwość użycia jak Node require
?
Mówiąc bardziej szczegółowo: powód require
jest tak dobry, że:
- Umożliwia dynamiczne ładowanie kodu z innych lokalizacji (co moim zdaniem jest lepsze stylistycznie niż łączenie całego kodu w HTML)
- Zapewnia spójny interfejs do budowania modułów
- Moduły łatwo zależą od innych modułów (więc mógłbym napisać na przykład API, które wymaga jQuery, abym mógł używać
jQuery.ajax()
- Załadowany javascript ma określony zakres , co oznacza, że mógłbym załadować
var dsp = require("dsp.js");
i byłbym w stanie uzyskać dostępdsp.FFT
, co nie kolidowałoby z moim lokalnymvar FFT
Nie znalazłem jeszcze biblioteki, która robi to skutecznie. Rozwiązania, których zwykle używam, to:
coffeescript-concat - dość łatwo jest wymagać innego js, ale musisz go skompilować, co oznacza, że jest mniej świetny do szybkiego programowania (np. budowanie API w testach)
RequireJS - Jest popularny, prosty i rozwiązuje 1-3, ale brak zakresu jest prawdziwym przełomem (uważam, że head.js jest podobny, ponieważ brakuje mu zakresu, chociaż nigdy nie miałem okazji go użyć. Podobnie LABjs może ładować i łagodzić
.wait()
problemy z zależnościami, ale nadal nie obsługuje zakresu)
O ile wiem, wydaje się, że istnieje wiele rozwiązań dla dynamicznego i / lub asynchronicznego ładowania javascript, ale mają one te same problemy z zakresem, co samo ładowanie js z HTML. Bardziej niż cokolwiek innego, chciałbym mieć sposób na załadowanie javascript, który w ogóle nie zanieczyszcza globalnej przestrzeni nazw, ale nadal pozwala mi ładować i używać bibliotek (tak jak wymaga tego węzeł).
AKTUALIZACJA 2020: Moduły są teraz standardem w ES6, a od połowy 2020 roku są natywnie obsługiwane przez większość przeglądarek . Moduły obsługują ładowanie synchroniczne i asynchroniczne (przy użyciu Promise). Obecnie zalecam, aby większość nowych projektów korzystała z modułów ES6 i transpilera w celu powrotu do pojedynczego pliku JS dla starszych przeglądarek.
Zgodnie z ogólną zasadą, dzisiejsza przepustowość jest zwykle znacznie szersza niż wtedy, gdy zadawałem to pytanie. Tak więc w praktyce możesz rozsądnie zdecydować się zawsze używać transpilera z modułami ES6 i skupić się na wydajności kodu, a nie na sieci.
POPRZEDNIA EDYCJA (lub jeśli nie lubisz modułów ES6): Od czasu napisania tego, intensywnie korzystałem z RequireJS (który ma teraz znacznie bardziej przejrzystą dokumentację). Moim zdaniem RequireJS był naprawdę trafnym wyborem. Chciałbym wyjaśnić, jak ten system działa dla ludzi, którzy są tak zdezorientowani jak ja:
Możesz używać require
w codziennym rozwoju. Moduł może być czymkolwiek zwracanym przez funkcję (zazwyczaj jest to obiekt lub funkcja) i jest objęty zakresem jako parametr. Możesz także skompilować swój projekt w jednym pliku do wdrożenia przy użyciu r.js
(w praktyce jest to prawie zawsze szybsze, mimo że require
można równolegle ładować skrypty).
Podstawową różnicą między RequireJS a stylem węzłów, których używa browserify (fajny projekt sugerowany przez tjameson), jest sposób, w jaki moduły są projektowane i wymagane:
- RequireJS używa AMD (Async Module Definition). W AMD
require
pobiera listę modułów (pliki javascript) do załadowania i funkcję wywołania zwrotnego. Po załadowaniu każdego z modułów wywołuje wywołanie zwrotne z każdym modułem jako parametr funkcji zwrotnej. Dzięki temu jest naprawdę asynchroniczny i dlatego dobrze nadaje się do sieci. - Węzeł używa CommonJS. W CommonJS
require
jest to wywołanie blokujące, które ładuje moduł i zwraca go jako obiekt. Działa to dobrze w przypadku Node, ponieważ pliki są odczytywane z systemu plików, co jest wystarczająco szybkie, ale działa słabo w Internecie, ponieważ synchroniczne ładowanie plików może zająć znacznie więcej czasu.
W praktyce wielu programistów korzystało z Node (a tym samym z CommonJS), zanim kiedykolwiek zobaczyli AMD. Ponadto wiele bibliotek / modułów jest napisanych dla CommonJS (przez dodanie rzeczy do exports
obiektu), a nie dla AMD (przez zwrócenie modułu z define
funkcji). Dlatego wielu deweloperów korzystających z Node chce korzystać z bibliotek CommonJS w sieci. Jest to możliwe, ponieważ ładowanie z <script>
tagu jest blokowane. Rozwiązania takie jak browserify pobierają moduły CommonJS (Node) i opakowują je, aby można było dołączyć je do tagów skryptów.
Dlatego też, jeśli tworzysz swój własny, wieloplikowy projekt dla sieci, zdecydowanie polecam RequireJS, ponieważ jest to naprawdę modułowy system dla sieci (choć, uczciwie mówiąc, uważam, że AMD jest o wiele bardziej naturalne niż CommonJS). Ostatnio to rozróżnienie straciło na znaczeniu, ponieważ RequireJS pozwala teraz zasadniczo używać składni CommonJS. Dodatkowo, RequireJS może służyć do ładowania modułów AMD w Node (chociaż wolę node-amd-loader ).
źródło
Odpowiedzi:
Sprawdź ender . Robi to często.
Ponadto przeglądarka jest całkiem dobra. Użyłem „ require-kiss” ¹ i działa. Prawdopodobnie są inni.
Nie jestem pewien co do RequireJS. To nie to samo, co węzeł. Możesz napotkać problemy z ładowaniem z innych lokalizacji, ale może to zadziałać. O ile istnieje metoda dostarczania lub coś, co można wywołać.
TL; DR - polecam przeglądarkę lub wymagam pocałunku.
Aktualizacja:
1: pocałunek wymagający jest teraz martwy, a autor usunął go. Od tamtej pory używam RequireJS bez problemów. Autor require-kiss napisał pakmanager i pakman . Pełne ujawnienie, współpracuję z programistą.
Osobiście wolę RequireJS. Jest znacznie łatwiejszy do debugowania (możesz mieć oddzielne pliki w trakcie opracowywania i jeden plik wdrożony w środowisku produkcyjnym) i jest zbudowany na solidnym „standardzie”.
źródło
Napisałem mały skrypt, który umożliwia asynchroniczne i synchroniczne ładowanie plików Javascript, co może być tutaj przydatne. Nie ma żadnych zależności i jest kompatybilny z Node.js i CommonJS. Instalacja jest dość łatwa:
$ npm install --save @tarp/require
Następnie po prostu dodaj następujące wiersze do kodu HTML, aby załadować moduł główny:
<script src="/node_modules/@tarp/require/require.min.js"></script> <script>Tarp.require({main: "./scripts/main"});</script>
Wewnątrz modułu głównego (i oczywiście dowolnego modułu podrzędnego) możesz użyć
require()
co znasz z CommonJS / NodeJS. Pełną dokumentację i kod można znaleźć na GitHub .źródło
myFunction
doalert("hello")
. Dzwonięmain.myFunction()
? To nie zadziała?Tarp.require({ expose: true });
, aby działał? Jak w twoim teście?Odmiana świetnej odpowiedzi Ilyi Kharlamova , z pewnym kodem, który sprawi, że będzie dobrze działać z narzędziami programistycznymi 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
źródło
Zdaję sobie sprawę, że mogą być początkujący, którzy chcą uporządkować swój kod. Jest rok 2020 i jeśli zastanawiasz się nad modułową aplikacją JS, powinieneś już teraz zacząć od npm i Webpack .
Oto kilka prostych kroków, aby rozpocząć:
npm init -y
aby zainicjować projekt npmnpm install webpack webpack-cli
Zwróć szczególną uwagę na
_bundle.js
plik - będzie to ostateczny plik JS wygenerowany przez webpacka, nie będziesz go bezpośrednio modyfikować (czytaj dalej).<project-root>/app.js
w którym zaimportujesz inne moduły:const printHello = require('./print-hello'); printHello();
print-hello.js
moduł:module.exports = function() { console.log('Hello World!'); }
<project-root>/webpack.config.js
i skopiuj i wklej następujące elementy:var path = require('path'); module.exports = { entry: './app.js', output: { path: path.resolve(__dirname), filename: '_bundle.js' } };
W powyższym kodzie są 2 punkty:
app.js
to miejsce, w którym napiszesz swój kod JS. Zaimportuje inne moduły, jak pokazano powyżej._bundle.js
to ostateczny pakiet wygenerowany przez webpack. Oto, co zobaczy Twój html na końcu.-7. Otwórz
package.js
i zamieńscripts
na następujące polecenie:"scripts": { "start": "webpack --mode production -w" },
app.js
i wygenerować_bundle.js
plik za pomocą polecenia:npm start
.źródło
(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]; } })();
Lepiej nie używać w produkcji ze względu na blokowanie. (W node.js, require () jest wywołaniem blokującym).
źródło
Webmake pakuje moduły w stylu węzła do przeglądarki, spróbuj.
źródło
Require-stub - zapewnia zgodność węzła
require
w przeglądarce, rozwiązuje zarówno moduły, jak i ścieżki względne. Używa techniki podobnej do TKRequire (XMLHttpRequest). Powstały kod można w pełni przeglądać w przeglądarce, corequire-stub
może służyć jako zamiennikwatchify
.źródło
Oto rozszerzenie fantastycznej odpowiedzi Lucio M. Tato, które pozwala na rekurencyjne ładowanie modułów ze ścieżkami względnymi.
Oto projekt github zawierający rozwiązanie i przykład, jak go używać:
https://github.com/trausti/TKRequire.js
Aby użyć TKRequire.js, umieść następujący wiersz w nagłówku
Następnie załaduj moduły tak jak w node.js:
źródło