Raw js imported as a real module

Modern javascript libraries are all made of modules. They can be plugged inside any project : web, server, batch or program.

That would be really straightforward to include any dependency as a single line of configuration inside a package.json file.

Unfortunately, some teams want to expose web javascript code in a raw format : no ‘export’, no ‘module.exports’, and even nothing injected inside ‘global’ or ‘window’. ES5-like format.

Naive var(s) and function(s) are declared. Private companies do so, and they minify/obfuscate their code.
Some teams even make a javascript code generator when the source code simply cannot be shared with other companies.

//this is a raw javascript file
var foo = "some important data"; 

function bar(){ 
  return "successful."; 
}; 
//This script is unmodifiable
//You are expected to use these symbols, without any access to them.

A simple option would suggest you to copy/paste the library inside your app.
Too bad it affects a lot the quality of your delivery : big chunks, troubles when the library is upgraded but not in your code, ‘package.json’ not explicit (some libs are not visible in the manifest although they are effectively included)

I have found another solution that I wish to share.
1°) Bundle that library in package.json (you can set the URL inside the version).
2°) Then import that lib in your code, but not with the ‘import’ or ‘require’ shortcut… write that boilerplate code :

//it is like an es6 import, excepted the fact that it also collects non exported variables and functions
const _imports = moduleImports => Object.assign({}, ...moduleImports.map(moduleImport => {
    //build a closure outside the non-structured code
    const theModule = new (eval('(function(){' + fs.readFileSync(`${moduleImport}.js`) + ';this.eval = (name) => eval(name)})'))()

    //pick the functions and var names
    const stringified = theModule.constructor.toString()
    const functions = (stringified.match(/function\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(/g)||[]).map(oneFunction => oneFunction.replace(/^function/g, '').replace('(', '').trim())
    const variables = (stringified.match(/(?:var|let|const)\s+([a-zA-Z_][.a-zA-Z_0-9]*)\s*=/g)||[]).map(oneFunction => oneFunction.replace(/^(var|let|const)\s/g, '').replace('=', '').trim())

    //resolve the references inside the module
    return Object.assign({}, ...functions.concat(variables).map(symbol => {try{return {[symbol]:theModule.eval(symbol)}}catch(e){}}).filter(symbol => symbol))
}))

3°) Call the _imports function where needed

// top of your js file
const { foo, bar } = _imports(['my-es5-module-1', 'my-es5-module-2'])
// your other imports
import { Component } from 'react'
// and it works...
console.log(foo)
console.log(bar())

There you go, use the invisible members of the lib like if they were really exported.
In this example, it also works when the lib is a set of javascript files that are dependent on each other but without import.

By the way,
Maybe you noticed that the layout of the blog has changed once again.
I am pretty sure that my visitors will prefer some rich content rather then a beautiful decoration, given the fact that the blog no longer talks about artistic concerns.
That is why I chose the most sober design I could find.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*