Los módulos generalmente comienzan algo como esto
(function(root, factory) { /* globals define */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], factory); } else if (typeof module === 'object' && typeof exports !== 'undefined') { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.Papa = factory(); } Estoy tratando de implementar require para manejar módulos similares a CommonJS de estilo de nodo.
Encuentre la carpeta del paquete, analice el paquete.json para conocer el punto de entrada y las dependencias, descienda recursivamente con un caché compartido para cargar las dependencias... eso funciona.
Pero después de haber cargado el script para un módulo, tengo problemas para ejecutarlo de tal manera que module.exports
Todo esto terminará ejecutándose en Jint (un intérprete de JS), por lo que el nodo no proporciona los muebles habituales, tengo que construirlo todo yo mismo. No hay depuración por pasos con Jint, así que estoy usando el nodo de VS Code y fingiendo a Jint de esta manera.
import * as fs from "fs"; var code = fs.readFileSync("node_modules/papaparse/papaparse.js").toString(); let x = 3; console.log(eval("x*x")) let result = eval(` let module = { exports: "dunno" }; ${code} console.log(module.exports); `); Está en un archivo test.js y package.json nomina este archivo como principal y especifica un tipo de módulo. Se inicia, lee el código del módulo, crea el module y ejecuta el código, que rápidamente se queja de que no Cannot set properties of undefined (setting 'Papa') .
Mirando el fragmento anterior, eso nos dice que está ejecutando la última cláusula else, lo que significa que no está viendo el module . Pensé que podría ser algún tipo de alcance para eval , que es de donde vino esto
let x = 3; console.log(eval("x*x")) pero eso escribe debidamente 9 en la consola, por lo que la pregunta es por qué el module no está dentro del alcance.
Esta es una de esas rarezas de cierre de JavaScript; ¿alguien puede guiarme sobre cómo proporcionar el objeto del module para que la segunda cláusula surta efecto poblando module.exports con el resultado de factory() ?
Sé que dije que se está ejecutando en ausencia de Node, pero lo estoy depurando usando Node principalmente porque eso es lo que obtienes cuando inicias un archivo js en VS Code. Como ya se mencionó, el objetivo de producción es Jint. El entorno de depuración es la aproximación más cercana que puedo manejar, y me abstengo de usar instalaciones que no estarán disponibles en producción.
En el entorno de depuración, creé un archivo package.json que determina si se trata como CommonJS o ES6. Los experimentos muestran que el entorno de producción se comporta más como ES6 que como commonjs. El problema es que la mayoría de los paquetes esperan que se ejecuten en un navegador o en un nodo. No consideran la posibilidad de otro entorno sin cabeza. El código anterior decide que su navegador está alojado e intenta instalar Papa en un DOM que no está allí.
La solución es envolver el módulo así (estoy construyendo una cadena en C#).
string wrapped = @"(function () { var module = { exports: { } }; " + jsSource + @" var strays = Object.keys(this).filter(itemName => itemName !== 'module'); if (strays.length === 1) module.exports = this[strays[0]] else strays.forEach(itemName => module.exports[itemName] = this[itemName]); return module.exports; }).apply({});"; Envolverlo en una función anónima y usar apply para configurar this para la llamada permite que la "escritura DOM" tenga éxito, y un pequeño código de seguimiento busca estos extraviados, reuniéndolos en exportaciones de módulos antes de volver a la operación normal.