Created
August 20, 2012 03:15
-
-
Save cyjake/3400004 to your computer and use it in GitHub Desktop.
A tool to minimize and bundle your SeaJS modules, in Ruby
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
class River | |
DEFAULT_CONFIG = { | |
:root => 'cc', | |
:base => Rails.root.join('public'), | |
:preloads => ['ent'] | |
} | |
def initialize(attrs = nil) | |
attrs ||= DEFAULT_CONFIG.dup | |
@root = attrs[:root] | |
@base = attrs[:base] | |
@preloads = attrs[:preloads] || [] | |
end | |
def resolve(mods) | |
@modules = [] | |
@codes = [] | |
if mods.is_a?(String) | |
mods = [mods] | |
end | |
mods.each do |mod| | |
resolve_mod(mod) | |
end | |
end | |
def resolve_mod(mod) | |
return if @preloads.include?(mod) || @modules.include?(mod) | |
mod = parse_mod(mod) | |
path = File.join(@base, "#{mod}.js") | |
code = File.open(path).read | |
unless code =~ /^define\((['"])[^'"]+\1/ | |
code = polish(mod, code) | |
# fio = File.open(path, 'w') | |
# fio.write(code) | |
end | |
@codes.unshift(code) | |
@modules.unshift(mod) | |
deps = parse_deps_from_define(code) | |
deps.each do |dep| | |
dep = expand_path(mod, dep) | |
resolve_mod(dep) | |
end | |
end | |
def append(mod, code) | |
@modules << mod | |
@codes << polish(mod, code) | |
end | |
def bundle | |
@preloads.each do |file| | |
code = File.open(File.join(@base, "#{file}.js")).read | |
@codes.unshift(code) | |
end | |
@codes.join("\n") | |
end | |
# mark the module id | |
# parse and set the module dependencies if not present | |
def polish(mod, code = nil) | |
mod = parse_mod(mod) | |
if code.present? | |
return polish_code(mod, code) | |
end | |
path = File.join(@base, "#{mod}.js") | |
code = File.open(path).read | |
unless code =~ /^define\((['"])[^'"]+\1/ | |
code = polish_code(mod, code) | |
fio = File.open(path, 'w') | |
fio.write(code) | |
fio.close | |
end | |
code | |
end | |
def polish_code(mod, code) | |
mod = parse_mod(mod) | |
if code =~ /^define\(function/ | |
deps = parse_deps(code) | |
deps -= @preloads | |
code.sub!(/^(define\()/, "\\1'#{mod}', #{deps.to_json}, ") | |
elsif code =~ /^define\([\[\{]/ | |
code.sub!(/^(define\()/, "\\1'#{mod}', ") | |
end | |
code | |
end | |
def parse_mod(mod) | |
start = mod.index(@root) || 0 | |
fini = mod.rindex('.js') || mod.length | |
mod.slice(start, fini - start) | |
end | |
def expand_path(mod, dep) | |
context = mod.include?('/') ? mod.slice(0, mod.rindex('/')) : '' | |
dep_bare = dep.slice(dep.index('/') || 0, dep.length) | |
ret = '' | |
if dep.starts_with?('./') | |
ret = context + dep_bare | |
elsif dep.starts_with?('../') | |
ret = context.slice(0, context.rindex('/')) + dep_bare | |
else | |
ret = dep | |
end | |
ret | |
end | |
def parse_deps_from_define(code) | |
pattern = /^define\((['"])[^'"]+\1,\s*(\[[^\]]+\])/ | |
match = pattern.match(code) | |
deps = [] | |
if match | |
deps = match[2] | |
deps = JSON.parse(deps.gsub("'", '"')) | |
deps.delete_if do |d| | |
d.blank? | |
end | |
else | |
pattern = /^define\((['"])[^'"]+\1,\s*(['"])([^\1]+)\1\.split/ | |
match = pattern.match(code) | |
if match | |
deps = match[3].split(/,\s*/) | |
end | |
end | |
deps | |
end | |
def parse_deps(code) | |
# Parse these `requires`: | |
# var a = require('a'); | |
# someMethod(require('b')); | |
# require('c'); | |
# ... | |
# Doesn't parse: | |
# someInstance.require(...); | |
pattern = /(?:^|[^.])\brequire\s*\(\s*(["'])([^"'\s\)]+)\1\s*\)/ | |
code = sans_comments(code) | |
matches = code.scan(pattern) | |
matches.map! do |m| | |
m[1] | |
end | |
matches.uniq.compact | |
end | |
# http://lifesinger.github.com/lab/2011/remove-comments-safely/ | |
def sans_comments(code) | |
code.gsub(/(?:^|\n|\r)\s*\/\*[\s\S]*?\*\/\s*(?:\r|\n|$)/, "\n") | |
.gsub(/(?:^|\n|\r)\s*\/\/.*(?:\r|\n|$)/, "\n") | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment