r9kkha
Last Updated: February 25, 2016
·
833
· zaibacu

Compiling a bunch of javascript/css files to a single file

Well this situation doesn't occur that often, so it begs a question WHY?

I'll give you a simple example: I was developing a Qt HTML 5 desktop app. HTML 5 was chosen due to its flexibility and... well... It looked fun to try that. However I came to conclusion, that I want to have possibility to use app offline, so I was forced to store all that HTML 5 code locally. It lead me to few problems:

  • User is provided with not just binary, but whole bunch of folders (html/ js/ css/).
  • Users are able to view and modify most of the app's logics. (Well there were no security risks, but still...)

At quick glimpse I couldn't found nothing to solve these problems, so I've wrote a very simple Python script which goes through dependecy tree and add everything to single file and encrypts it (Used a very simple base64 encryption just to prove the point). Script itself can be found here: https://gist.github.com/zaibacu/9412574 (hopefully more up to date version)

import re
import codecs
import base64

def load_js(src):
    stream = ""
    with codecs.open(src, encoding="utf-8", mode="r") as f:
        stream = f.read()

    return "<script>" + stream + "</script>"

def load_css(src):
    stream = ""
    with codecs.open(src, encoding="utf-8", mode="r") as f:
        stream = f.read()
    return "<style>\n"+ stream + "\n</style>"

def dependency_walk(root_file):
    with open(root_file) as f:
        stream = f.read()

    #Handle scripts
    while True:
        scripts = re.compile("(<script type=\"text/javascript\" src=\")(?P<url>[a-z./]+)\"></script>")
        result = scripts.search(stream)
        if not result:
            break

        stream = stream.replace(result.group(0), load_js(result.group("url")))

    #Handle style
    while True:
        styles = re.compile("<link href=\"(?P<url>[a-z./]+)\" rel=\"stylesheet\">")
        result = styles.search(stream)
        if not result:
            break
        stream = stream.replace(result.group(0), load_css(result.group("url")))
    return stream

def encrypter(stream):
    return base64.b64encode(stream.encode("utf-8")).decode("utf-8")

print("reading")
html = dependency_walk("index.html")
print("encrypting")
html = encrypter(html)
print("writing")
with codecs.open("data.bin", encoding="utf-8", mode="w") as f:
    f.write(html)

Nothing very fancy and not optimized, but seems to do the job.

Maybe it will be helpful for somebody