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...

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.

Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.