diff --git a/bundler/bundle.js b/bundler/bundle.js new file mode 100644 index 00000000..c0cf3fa8 --- /dev/null +++ b/bundler/bundle.js @@ -0,0 +1,87 @@ +"use strict" + +var fs = require("fs") +var path = require("path") + +module.exports = function(input, output) { + function run(e, file) { + var modules = {} + var usedVariables = {} + + function resolve(dir, data) { + var replacements = [] + data = data.replace(/((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)require\(([^\)]+)\)/g, function(match, def, variable, eq, dep) { + usedVariables[variable] = usedVariables[variable] ? usedVariables[variable]++ : 1 + + var filename = new Function("return " + dep).call() + + //resolve npm dependencies + if (filename[0] !== ".") { + var meta = JSON.parse(fs.readFileSync("./node_modules/" + filename + "/package.json")) + var dependencyEntry = "./node_modules/" + filename + "/" + (meta.main || filename + ".js") + try {fs.statSync(dependencyEntry).isFile()} catch (e) {dependencyEntry = "./node_modules/" + filename + "/index.js"} + return resolve(path.dirname(dependencyEntry), exportCode(dependencyEntry, def + variable + eq)) + } + + //resolve local dependencies + var normalized = path.resolve(dir, filename) + var pathname = path.dirname(normalized) + if (modules[normalized] === undefined) { + modules[normalized] = variable + var exported = exportCode(dir + "/" + filename + ".js", def + variable + eq) + return resolve(pathname, exported) + } + else { + if (modules[normalized] !== variable) { + replacements.push({variable: variable, replacement: modules[normalized]}) + } + return "" + } + }) + if (replacements.length > 0) { + for (var i = 0; i < replacements.length; i++) { + data = data.replace(new RegExp("\\b" + replacements[i].variable + "\\b", "g"), replacements[i].replacement) + } + } + return data + .replace(/(?:var|let|const)[\t ]([\w_$\.]+)(\s*=\s*)\1([\r\n;]+)/g, "$3") // remove assignments to itself + .replace(/([\r\n]){2,}/g, "$1") // remove multiple consecutive line breaks + .replace(/\}[\r\n]+\(/g, "}(") // remove space from iife + } + + function exportCode(file, assignment) { + return fixCollisions(fs.readFileSync(file, "utf8")) + .replace(/("|')use strict\1;?\s*/gm, "") // remove extraneous "use strict" + .replace(/module\.exports\s*=\s*/gm, assignment) + } + + function fixCollisions(code) { + for (var variable in usedVariables) { + var collision = new RegExp("\\b" + variable + "\\b(?![\"'`])", "g") + var exported = new RegExp("module\\.exports\\s*=\\s*" + variable) + if (collision.test(code) && !exported.test(code)) { + var fixed = variable + usedVariables[variable]++ + code = code.replace(collision, fixed) + } + } + return code + } + + function setVersion(code) { + var metadata = JSON.parse(fs.readFileSync("./package.json")) + return code.replace("bleeding-edge", metadata.version) + } + + function bundle(input, output) { + console.log("bundling...") + var code = setVersion(resolve(path.dirname(input), fs.readFileSync(input, "utf8"))) + if (new Function(code)) fs.writeFileSync(output, code, "utf8") + console.log("done") + } + + if (file !== output && file !== output.replace(/\.js$/, ".min.js")) bundle(input, output) + } + run() + + //fs.watch(process.cwd(), {recursive: true}, run) +} diff --git a/bundler/bundler.js b/bundler/bundler.js deleted file mode 100644 index 1ecc9648..00000000 --- a/bundler/bundler.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict" - -var fs = require("fs") -var path = require("path") - -var modules = {} -var usedVariables = {} - -function resolve(dir, data) { - var replacements = [] - data = data.replace(/((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)require\(([^\)]+)\)/g, function(match, def, variable, eq, dep) { - usedVariables[variable] = usedVariables[variable] ? usedVariables[variable]++ : 1 - - var filename = new Function("return " + dep).call() - - //resolve npm dependencies - if (filename[0] !== ".") { - var meta = JSON.parse(fs.readFileSync("./node_modules/" + filename + "/package.json")) - var dependencyEntry = "./node_modules/" + filename + "/" + (meta.main || filename + ".js") - try {fs.statSync(dependencyEntry).isFile()} catch (e) {dependencyEntry = "./node_modules/" + filename + "/index.js"} - return resolve(path.dirname(dependencyEntry), exportCode(dependencyEntry, def + variable + eq)) - } - - //resolve local dependencies - var normalized = path.resolve(dir, filename) - var pathname = path.dirname(normalized) - if (modules[normalized] === undefined) { - modules[normalized] = variable - var exported = exportCode(dir + "/" + filename + ".js", def + variable + eq) - return resolve(pathname, exported) - } - else { - if (modules[normalized] !== variable) { - replacements.push({variable: variable, replacement: modules[normalized]}) - } - return "" - } - }) - if (replacements.length > 0) { - for (var i = 0; i < replacements.length; i++) { - data = data.replace(new RegExp("\\b" + replacements[i].variable + "\\b", "g"), replacements[i].replacement) - } - } - return data - .replace(/(?:var|let|const)[\t ]([\w_$\.]+)(\s*=\s*)\1([\r\n;]+)/g, "$3") // remove assignments to itself - .replace(/([\r\n]){2,}/g, "$1") // remove multiple consecutive line breaks - .replace(/\}[\r\n]+\(/g, "}(") // remove space from iife -} - -function exportCode(file, assigment) { - return fixCollisions(fs.readFileSync(file, "utf8")) - .replace(/("|')use strict\1;?\s*/gm, "") // remove extraneous "use strict" - .replace(/module\.exports\s*=\s*/gm, assigment) -} - -function fixCollisions(code) { - for (var variable in usedVariables) { - var collision = new RegExp("\\b" + variable + "\\b(?![\"'`])", "g") - var exported = new RegExp("module\\.exports\\s*=\\s*" + variable) - if (collision.test(code) && !exported.test(code)) { - var fixed = variable + usedVariables[variable]++ - code = code.replace(collision, fixed) - } - } - return code -} - -function setVersion(code) { - var metadata = JSON.parse(fs.readFileSync("./package.json")) - return code.replace("bleeding-edge", metadata.version) -} - -function bundle(input, output) { - var code = setVersion(resolve(".", fs.readFileSync(input, "utf8"))) - if (new Function(code)) fs.writeFileSync(output, code, "utf8") -} - -bundle("index.js", "mithril.js") diff --git a/bundler/cli.js b/bundler/cli.js new file mode 100644 index 00000000..8866b0b8 --- /dev/null +++ b/bundler/cli.js @@ -0,0 +1,21 @@ +"use strict" + +var bundle = require("./bundle") +var minify = require("./minify") + +var aliases = {o: "output"} +var params = {} +var args = process.argv.slice(2), command = null +console.log(args) +for (var i = 0; i < args.length; i++) { + if (args[i][0] === '"') args[i] = args[i].slice(1, -1) + if (args[i][0] === "-") command = args[i].replace(/\-+/g, "") + else if (command != null) { + params[aliases[command] || command] = args[i] + command = null + } + else params.input = args[i] +} + +bundle(params.input, params.output) +minify(params.output, params.output.replace(/\.js$/, ".min.js")) \ No newline at end of file diff --git a/bundler/minify.js b/bundler/minify.js index fc178ce6..59586451 100644 --- a/bundler/minify.js +++ b/bundler/minify.js @@ -2,48 +2,64 @@ var http = require("http") var querystring = require("querystring") var fs = require("fs") -var code = fs.readFileSync("./mithril.js", "utf8") - -var data = { - output_format: "json", - output_info: ["compiled_code", "warnings", "errors", "statistics"], - compilation_level: "SIMPLE_OPTIMIZATIONS",//ADVANDED_OPTIMIZATIONS - warning_level: "default", - output_file_name: "default.js", - js_code: code, -} - -var body = querystring.stringify(data) - -var req = http.request({ - method: "POST", - protocol: "http:", - hostname: "closure-compiler.appspot.com", - path: "/compile", - headers: { - "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - "Content-Length": body.length +module.exports = function(input, output) { + function format(n) { + return n.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") } -}, function(res) { - res.on("data", function(chunk) { - response += chunk.toString() - }) - res.on("end", function() { - var results = JSON.parse(response) - var stats = results.statistics - console.log("Original size: " + format(stats.originalGzipSize) + " bytes gzipped (" + format(stats.originalSize) + " bytes uncompressed)") - console.log("Compiled size: " + format(stats.compressedGzipSize) + " bytes gzipped (" + format(stats.compressedSize) + " bytes uncompressed)") - - fs.writeFileSync("mithril.min.js", results.compiledCode, "utf8") - }) -}) -var response = "" + function minify(input, output) { + var code = fs.readFileSync(input, "utf8") -req.write(body) -req.end() -console.log("compiling...") + var data = { + output_format: "json", + output_info: ["compiled_code", "warnings", "errors", "statistics"], + compilation_level: "SIMPLE_OPTIMIZATIONS",//ADVANDED_OPTIMIZATIONS + warning_level: "default", + output_file_name: "default.js", + js_code: code, + } -function format(n) { - return n.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") -} \ No newline at end of file + var body = querystring.stringify(data) + + var response = "" + var req = http.request({ + method: "POST", + protocol: "http:", + hostname: "closure-compiler.appspot.com", + path: "/compile", + headers: { + "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", + "Content-Length": body.length + } + }, function(res) { + res.on("data", function(chunk) { + response += chunk.toString() + }) + res.on("end", function() { + var results = JSON.parse(response) + if (results.errors) { + for (var i = 0; i < results.errors.length; i++) console.log(results.errors[i]) + } + else { + fs.writeFileSync(output, results.compiledCode, "utf8") + + var stats = results.statistics + console.log("done") + console.log("Original size: " + format(stats.originalGzipSize) + " bytes gzipped (" + format(stats.originalSize) + " bytes uncompressed)") + console.log("Compiled size: " + format(stats.compressedGzipSize) + " bytes gzipped (" + format(stats.compressedSize) + " bytes uncompressed)") + } + }) + }) + + + req.write(body) + req.end() + console.log("minifying...") + } + function run() { + minify(input, output) + } + run() + + //fs.watchFile(input, run) +} diff --git a/index.js b/index.js index 7fcfb640..139be0be 100644 --- a/index.js +++ b/index.js @@ -24,7 +24,9 @@ m.withAttr = require("./util/withAttr") m.render = renderService.render m.redraw = redrawService.publish -if (typeof module === "object") module.exports = m +if (typeof module === "object") { + module.exports = m +} else window.m = m })() diff --git a/mithril.js b/mithril.js index 7a03ff45..f47c4ff9 100644 --- a/mithril.js +++ b/mithril.js @@ -1048,6 +1048,8 @@ m.withAttr = function(attrName, callback, context) { } m.render = renderService.render m.redraw = redrawService.publish -if (typeof module === "object") module.exports = m +if (typeof module === "object") { + module.exports = m +} else window.m = m })() diff --git a/ospec/bin/ospec b/ospec/bin/ospec index a5fb99b8..49b3ddc0 100644 --- a/ospec/bin/ospec +++ b/ospec/bin/ospec @@ -33,7 +33,7 @@ function traverseDirectory(pathname, callback) { traverseDirectory(".", function(pathname, stat, children) { if (pathname.indexOf("node_modules") > -1) return if (pathname.match(/(?:^|\/)tests\/.*\.js$/)) { - require("../../" + pathname) + require(path.normalize(process.cwd()) + "/" + pathname) } }) .then(o.run) diff --git a/package.json b/package.json index 8ee589d1..6d2eadce 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,7 @@ "license": "MIT", "main": "index.js", "scripts": { - "build": "node bundler/bundler", - "minify": "node bundler/minify", + "build": "node bundler/cli index.js -o mithril.js", "lintdocs": "node bundler/lintdocs", "lint": "eslint .", "test": "node ospec/bin/ospec",