Skip to content

Instantly share code, notes, and snippets.

@jrydberg
Created April 21, 2011 17:06
Show Gist options
  • Save jrydberg/935004 to your computer and use it in GitHub Desktop.
Save jrydberg/935004 to your computer and use it in GitHub Desktop.
Hack to pack commonjs-modules for ukijs into a single file
# Copyright (C) 2011 Johan Rydberg <johan.rydberg@gmail.com>
# Released under the Apache 2.0 license.
"""Simple hack to pack together a ukijs application into a single file."""
import re
import os
import cssutils
import base64
import sys
import optparse
# Regexp for 'require' expressions.
require_re = re.compile(r"require\([\s]*['\"](?P<path>[\S\.]+)['\"][\s]*\)")
# Regexp for 'requireCss' stmts.
requireCss_re = re.compile(r"requireCss\([\s]*['\"](?P<path>[\S\.]+)['\"][\s]*\);")
# Regexp for 'requireText' expressions.
requireText_re = re.compile(r"requireText\([\s]*['\"](?P<path>[\S\.]+)['\"][\s]*\)")
# Regexp for 'url' expressions in the CSS values.
url_re = re.compile(r"url\((?P<path>[^)]+)\)")
class RequireProcessor:
def __init__(self, include_paths):
self.required = {}
self.modules = {}
self.index = 0
self.include_paths = include_paths
self.css = []
def resolve_filename(self, modname, current_path, ext='.js'):
include_paths = [current_path] + self.include_paths
for dirname in include_paths:
modpath = os.path.normpath(os.path.join(
dirname, modname))
if os.path.exists(modpath + ext):
return modpath
raise Exception("can not find", modname)
def data_uri_css_images(self, currentdir, value):
def replace(match):
filepath = os.path.join(currentdir, match.groupdict()['path'])
content = open(filepath).read()
fileext = os.path.splitext(filepath)[1][1:]
return 'url(data:image/%s;base64,%s)' % (
fileext, base64.b64encode(content))
return url_re.sub(replace, value)
def _process_css(self, currentdir, code):
sheet = cssutils.parseString(code)
for rule in sheet:
if rule.type == rule.STYLE_RULE:
if 'background' in rule.style:
background = rule.style['background']
new_background = self.data_uri_css_images(currentdir, background)
if new_background != background:
rule.style['background'] = new_background
return sheet.cssText
def process_file(self, filename):
content = open(filename + '.js').read()
index = self.index
self.required[filename] = index
self.index = self.index + 1
def module_repl(match, filename=filename):
modname = match.groupdict()['path']
modfilename = self.resolve_filename(modname, os.path.dirname(filename))
if modfilename not in self.required:
self.process_file(modfilename)
return 'require(%d)' % (self.required[modfilename])
def css_repl(match, filename=filename):
modname = match.groupdict()['path']
modfilename = self.resolve_filename(
modname, os.path.dirname(filename), ext='')
self.css.append(self._process_css(os.path.dirname(modfilename),
open(modfilename).read()))
return ''
def text_repl(match, filename=filename):
modname = match.groupdict()['path']
modfilename = self.resolve_filename(
modname, os.path.dirname(filename), ext='')
return repr(open(modfilename).read())
new_content = require_re.sub(module_repl, content)
new_content = requireCss_re.sub(css_repl, new_content)
new_content = requireText_re.sub(text_repl, new_content)
self.modules[index] = new_content
def write_content(self, outfile):
outfile.write(
"""var global = this;
function require(index) {
if (!require_cache[index]) {
var module = require_cache[index] = {
exports: {}
};
require_modules[index].call(module.exports,
global, module, require);
}
return require_cache[index].exports;
};
var require_modules = require.modules = [];
var require_cache = require.cache = [];
var __requiredCss = %s;
""" % (repr(''.join(self.css))))
def _wrap_module_content(content):
return """(function(global, module, require) {
var exports = this;
%(content)s
})
""" % (dict(content=content))
for i in range(processor.index):
outfile.write("require_modules[%d] = %s;\n" % (
i, _wrap_module_content(processor.modules[i])))
outfile.write("require(0);\n")
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option('--minify-css', dest='minify_css', action="store_true")
parser.add_option('-I', '--include-dir', dest='include_paths', action="append")
options, args = parser.parse_args()
if len(args) != 1:
sys.exit("No input.")
if options.minify_css:
cssutils.ser.prefs.useMinified()
processor = RequireProcessor(options.include_paths)
processor.process_file(args[0])
processor.write_content(sys.stdout)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment