¿Existen bibliotecas para javascript en el navegador que brinden la misma flexibilidad / modularidad / facilidad de uso que las de Node require
?
Para proporcionar más detalles: la razón require
es tan buena es que:
- Permite que el código se cargue dinámicamente desde otras ubicaciones (lo cual es estilísticamente mejor, en mi opinión, que vincular todo su código en el HTML)
- Proporciona una interfaz coherente para la construcción de módulos.
- Es fácil que los módulos dependan de otros módulos (por lo que podría escribir, por ejemplo, una API que requiera jQuery para poder usar
jQuery.ajax()
- El javascript cargado tiene un alcance , lo que significa que podría cargar
var dsp = require("dsp.js");
y podría accederdsp.FFT
, lo que no interferiría con mivar FFT
Todavía tengo que encontrar una biblioteca que haga esto de manera efectiva. Las soluciones alternativas que suelo usar son:
coffeescript-concat : es bastante fácil requerir otros js, pero debe compilarlo, lo que significa que es menos bueno para un desarrollo rápido (por ejemplo, compilar API en la prueba)
RequireJS : es popular, sencillo y resuelve 1-3, pero la falta de alcance es un verdadero factor decisivo (creo que head.js es similar porque carece de alcance, aunque nunca he tenido la oportunidad de usarlo. De manera similar, los LABj pueden cargar y mitigar los
.wait()
problemas de dependencia, pero aún no tiene alcance)
Por lo que puedo decir, parece haber muchas soluciones para la carga dinámica y / o asíncrona de javascript, pero tienden a tener los mismos problemas de alcance que simplemente cargar js desde HTML. Más que cualquier otra cosa, me gustaría una forma de cargar javascript que no contamine el espacio de nombres global en absoluto, pero que aún me permita cargar y usar bibliotecas (tal como lo hacen los requisitos del nodo).
ACTUALIZACIÓN 2020: Los módulos ahora son estándar en ES6 y, a partir de mediados de 2020, la mayoría de los navegadores los admiten de forma nativa . Los módulos admiten carga síncrona y asincrónica (usando Promise). Mi recomendación actual es que la mayoría de los proyectos nuevos deben usar módulos ES6 y usar un transpilador para recurrir a un solo archivo JS para navegadores heredados.
Como principio general, el ancho de banda de hoy también suele ser mucho más amplio que cuando hice esta pregunta originalmente. Por lo tanto, en la práctica, podría elegir razonablemente usar siempre un transpilador con módulos ES6 y concentrar su esfuerzo en la eficiencia del código en lugar de la red.
EDICIÓN ANTERIOR (o si no le gustan los módulos ES6): desde que escribí esto, he usado ampliamente RequireJS (que ahora tiene una documentación mucho más clara). RequireJS realmente fue la elección correcta en mi opinión. Me gustaría aclarar cómo funciona el sistema para las personas que están tan confundidas como yo:
Puede utilizarlo require
en el desarrollo diario. Un módulo puede ser cualquier cosa devuelta por una función (normalmente un objeto o una función) y tiene un alcance como parámetro. También puede compilar su proyecto en un solo archivo para su implementación r.js
(en la práctica, esto es casi siempre más rápido, aunque require
puede cargar scripts en paralelo).
La principal diferencia entre RequireJS y el estilo de nodo require como browserify (un proyecto genial sugerido por tjameson) es la forma en que se diseñan y requieren los módulos:
- RequireJS usa AMD (Definición de módulo asíncrono). En AMD,
require
toma una lista de módulos (archivos javascript) para cargar y una función de devolución de llamada. Cuando ha cargado cada uno de los módulos, llama a la devolución de llamada con cada módulo como parámetro para la devolución de llamada. Por lo tanto, es realmente asincrónico y, por lo tanto, se adapta bien a la web. - Node usa CommonJS. En CommonJS,
require
es una llamada de bloqueo que carga un módulo y lo devuelve como un objeto. Esto funciona bien para Node porque los archivos se leen fuera del sistema de archivos, que es lo suficientemente rápido, pero funciona mal en la web porque cargar archivos sincrónicamente puede llevar mucho más tiempo.
En la práctica, muchos desarrolladores han usado Node (y por lo tanto CommonJS) antes de ver AMD. Además, muchas bibliotecas / módulos están escritos para CommonJS (agregando cosas a un exports
objeto) en lugar de para AMD (devolviendo el módulo desde la define
función). Por lo tanto, muchos desarrolladores de Node convertidos en web quieren usar bibliotecas CommonJS en la web. Esto es posible, ya que <script>
se bloquea la carga desde una etiqueta. Soluciones como browserify toman módulos CommonJS (Node) y los envuelven para que pueda incluirlos con etiquetas de script.
Por lo tanto, si está desarrollando su propio proyecto de múltiples archivos para la web, le recomiendo encarecidamente RequireJS, ya que es realmente un sistema de módulos para la web (aunque, en términos justos, creo que AMD es mucho más natural que CommonJS). Recientemente, la distinción se ha vuelto menos importante, ya que RequireJS ahora le permite usar esencialmente la sintaxis CommonJS. Además, RequireJS se puede usar para cargar módulos AMD en Node (aunque prefiero node-amd-loader ).
fuente
Respuestas:
Echa un vistazo a ender . Hace mucho de esto.
Además, browserify es bastante bueno. He usado require-kiss ¹ y funciona. Probablemente hay otros.
No estoy seguro de RequireJS. Simplemente no es lo mismo que el de node. Puede tener problemas con la carga desde otras ubicaciones, pero podría funcionar. Siempre que haya un método provide o algo que se pueda llamar.
TL; DR : recomendaría browserify o require-kiss.
Actualizar:
1: require-kiss ahora está muerto y el autor lo ha eliminado. Desde entonces he estado usando RequireJS sin problemas. El autor de require-kiss escribió pakmanager y pakman . Divulgación completa, trabajo con el desarrollador.
Personalmente, me gusta más RequireJS. Es mucho más fácil de depurar (puede tener archivos separados en desarrollo y un solo archivo implementado en producción) y se basa en un "estándar" sólido.
fuente
Escribí un pequeño script que permite la carga asíncrona y síncrona de archivos Javascript, lo que podría ser de alguna utilidad aquí. No tiene dependencias y es compatible con Node.js y CommonJS. La instalación es bastante sencilla:
$ npm install --save @tarp/require
Luego, simplemente agregue las siguientes líneas a su HTML para cargar el módulo principal:
<script src="/node_modules/@tarp/require/require.min.js"></script> <script>Tarp.require({main: "./scripts/main"});</script>
Dentro de su módulo principal (y cualquier submódulo, por supuesto) puede usarlo
require()
como lo conoce de CommonJS / NodeJS. Los documentos completos y el código se pueden encontrar en GitHub .fuente
Una variación de la gran respuesta de Ilya Kharlamov , con algo de código para que funcione bien con las herramientas de desarrollo de 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
fuente
Me doy cuenta de que puede haber principiantes que busquen organizar su código. Esta es 2020 , y si usted está pensando en una aplicación modular JS, que debe empezar a trabajar con la NGP y webpack en este momento.
Aquí hay algunos pasos simples para comenzar:
npm init -y
para inicializar un proyecto npmnpm install webpack webpack-cli
Preste especial atención al
_bundle.js
archivo: este será un archivo JS final generado por el paquete web, no lo modificará directamente (siga leyendo).<project-root>/app.js
en el que importarás otros módulos:const printHello = require('./print-hello'); printHello();
print-hello.js
módulo de muestra :module.exports = function() { console.log('Hello World!'); }
<project-root>/webpack.config.js
y copie y pegue lo siguiente:var path = require('path'); module.exports = { entry: './app.js', output: { path: path.resolve(__dirname), filename: '_bundle.js' } };
En el código anterior, hay 2 puntos:
app.js
es donde escribirás tu código JS. Importará otros módulos como se muestra arriba._bundle.js
es su paquete final generado por webpack. Esto es lo que verá su html al final.-7. Abra su
package.js
y reempláceloscripts
con el siguiente comando:"scripts": { "start": "webpack --mode production -w" },
app.js
y generar el_bundle.js
archivo ejecutando:npm start
.fuente
(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]; } })();
Es mejor no utilizarlo en producción debido al bloqueo. (En node.js, require () es una llamada de bloqueo bien).
fuente
Webmake incluye módulos de estilo Node en el navegador, pruébalo.
fuente
Require-stub : proporciona compatibilidad con nodos
require
en el navegador, resuelve tanto módulos como rutas relativas. Utiliza una técnica similar a TKRequire (XMLHttpRequest). El código resultante es completamente navegable, ya querequire-stub
puede servir como reemplazo dewatchify
.fuente
Aquí hay una extensión de la fantástica respuesta de Lucio M. Tato que permite la carga recursiva de módulos con rutas relativas.
Aquí hay un proyecto de github para albergar la solución y un ejemplo de cómo usarlo:
https://github.com/trausti/TKRequire.js
Para usar TKRequire.js, incluya la siguiente línea en su encabezado
Luego cargue los módulos como en node.js:
fuente