En esta publicación, le mostraré cómo compilar "verdaderamente" el código Node.js (JavaScript) a V8 Bytecode. Esto le permite ocultar o proteger su código fuente de una mejor manera que la ofuscación u otros trucos no muy eficientes (como encriptar su código usando una clave secreta, que se incrustará en los archivos binarios de su aplicación, por eso dije "verdaderamente" arriba). Entonces, usando la herramienta bytenode, puede distribuir una versión binaria .jsc de sus archivos JavaScript. También puede agrupar todos sus archivos .js usando Browserify, luego compilar ese único archivo en .jsc. Compruebe en Github. el repositorio de bytenode Larga historia corta.. Instalar bytenode globalmente: [sudo] npm install -g bytenode Para compilar su archivo .js, ejecute este comando: bytenode --compile my-file.js my-file.jsc Instale bytenode en su proyecto también: npm install --save bytenode En su código, requiera bytenode, registrarse extensión en el sistema de módulos Node.js. Es por eso que lo instalamos localmente también. const bytenode = require('bytenode'); .jsc Ahora puede solicitar my-file.jsc como módulo: También puedes eliminar desde la construcción de producción. const myFile = require('./my-file.jsc'); my-file.js Y si quieres correr usando clic: my-file.js bytenode bytenode --run my-file.jsc Ahora ya sabes cómo compilar archivos, cómo requerir la versión compilada en su código y cómo ejecutar archivos desde la terminal. Pasemos a la larga historia. .js .jsc El motor V8 (en el que se basa Node.js) usa lo que se llama: compilación justo a tiempo (JIT), donde el código JavaScript se compila justo antes de la ejecución, luego se optimizará posteriormente. Empezando desde v5.7.0, el módulo vm introdujo una propiedad llamada en Función constructora, así que si haces algo como esto: Node.js produceCachedData vm.Script helloScript = vm. ;', { produceCachedData: }); let new Script(' . ( ) console log "Hello World!" true /* This is required for Node.js < 10.0.0 */ Ver en GitHub Luego, obtenga el código de bytes o buffer: cachedData helloBuffer = helloScript.cachedData; helloBuffer = helloScript.createCachedData(); let // or in Node.js >= 10 let Ver en GitHub Este se puede usar para crear un script idéntico que ejecutará las mismas instrucciones cuando se ejecute, pasándolo al Función constructora: helloBuffer vm.Script anotherHelloScript = vm.Script( , { : , : helloBuffer }); let new '' produceCachedData true cachedData // This will fail! Ver en GitHub Pero esto fallará, el motor V8 se quejará del primer argumento (esa cadena vacía ), cuando comprueba si es el mismo código que el que se utilizó para generar tampón en primer lugar. Sin embargo, este proceso de verificación es bastante fácil, lo que importa es la longitud del código. Entonces, esto funcionará: '' helloBuffer anotherHelloScript = vm.Script( .repeat( ), { : , : helloBuffer }); let new ' ' 28 produceCachedData true cachedData Ver en GitHub Le damos una cadena vacía con la misma longitud (28) que el código original ( ) . ¡Eso es todo! console.log("Hello World!"); Esto es interesante, utilizando el búfer almacenado en caché y la longitud del código original, pudimos crear un script idéntico. Ambos scripts se pueden ejecutar usando función. Entonces, si los ejecutó: .runInThisContext(); helloScript.runInThisContext(); anotherHelloScript.runInThisContext(); Ver en GitHub verás '¡Hola Mundo!' dos veces. (Tenga en cuenta que si ha utilizado la longitud incorrecta o si ha utilizado otra versión de Node.js/V8: no se ejecutará, y su propiedad se establecerá en ). anotherHelloScript cachedDataRejected true Ahora a nuestro último paso, cuando definimos usamos un valor codificado (28) como la longitud de nuestro código. ¿Cómo podemos cambiar esto, para que en el tiempo de ejecución no tengamos que saber exactamente cuánto tiempo tenía el código fuente original? anotherHelloScript Después de investigar un poco en el código fuente de V8, descubrí que la información del encabezado se define (en este archivo ): aquí code-serializer.h // The data header consists of uint32_t-sized entries: // [0] magic number and (internally provided) external reference count // [1] version hash // [2] source hash // [3] cpu features // [4] flag hash Ver en GitHub Pero, el búfer de Node.js es una matriz de tipo Uint8Array. Esto significa que cada entrada de la matriz tomará cuatro entradas en el buffer. Entonces, la longitud de la carga útil (que es hash en el índice , cual es bytes en el búfer de nodo) será: uint32 uint8 source [2] [8, 9, 10, 11] payloadLengthBytes = whateverBufferYouHave.slice( , ); let 8 12 Ver en GitHub Será algo como esto: , que es Little Endian, por lo que dice: . Esa es la longitud de nuestro código (28 en decimal). <Buffer 1c 00 00 00> 0x0000001c Para convertir estos cuatro bytes en un valor numérico, puede hacer algo como esto: firstByte + (secodeByte * 256) + (thirdByte * 256**2) + (forthByte * 256**3), O de una manera más elegante, puedes hacer esto: length = payloadLengthBytes.reduce( sum += number * **power , ); let ( ) => sum, number, power 256 0 Ver en GitHub Como hice en mi biblioteca, verifíquelo para ver la receta completa. aquí Alternativamente, podríamos usar función, que hace exactamente lo que queremos: buf.readIntLE() length = whateverBufferYouHave.readIntLE( , ); let 8 4 // 8 is the offset, 4 is the number of bytes to read Ver en GitHub Una vez que haya leído la longitud del código original (que se utilizó para generar el buffer), ahora puede crear su script: cachedData anotherHelloScript = vm.Script( .repeat(length), { : , : helloBuffer }); anotherHelloScript.runInThisContext(); let new ' ' produceCachedData true cachedData // later in your code Ver en GitHub Finalmente, ¿esta técnica tiene un impacto en el rendimiento? Bueno, en las versiones recientes de v8 (y Node.js), el rendimiento es casi el mismo. Usando el índice de octancia no encontré ninguna diferencia en el rendimiento. Sé que Google desaprobó octance (porque los navegadores y los motores JS estaban haciendo trampa), pero los resultados en nuestra situación son significativos, porque estamos comparando el mismo código en el mismo motor JS. Entonces, la respuesta final es: Bytenode NO tiene un impacto negativo en el rendimiento. Consulte mi , donde puede encontrar ejemplos de trabajo completos. He agregado un (que no tiene ninguna protección de código fuente) y para (que tiene una herramienta similar a nwjc, pero solo funciona con el código del lado del navegador). Agregaré más ejemplos (y pruebas) pronto, con suerte. repositorio de Github ejemplo para Electron NW.js