Created
April 21, 2011 17:06
-
-
Save jrydberg/935004 to your computer and use it in GitHub Desktop.
Hack to pack commonjs-modules for ukijs into a single file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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