Skip to content

Commit

Permalink
Merge remote-tracking branch 'MithrilJS/next' into streams-rewrite
Browse files Browse the repository at this point in the history
# Conflicts:
#	docs/stream.md
#	stream/stream.js
  • Loading branch information
porsager committed Nov 22, 2018
2 parents e6c09c5 + d66b7f6 commit f84ac07
Show file tree
Hide file tree
Showing 54 changed files with 3,552 additions and 547 deletions.
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ coverage/
docs/lib/
examples/
/mithril.js
/mithril.mjs
/mithril.min.js
/mithril.min.mjs
/stream/stream.mjs
node_modules/
8 changes: 0 additions & 8 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,9 +1 @@
.travis.yml @tivac
package.json @tivac
.npmignore @tivac
.eslintrc.js @tivac
.eslintignore @tivac
README.md @tivac
docs/ @tivac
performance/ @tivac
render/ @pygy
11 changes: 6 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ after_success:
--commands "echo committing" \
--commit-message "Bundled output for commit $TRAVIS_COMMIT [skip ci]" \
--branch "next"
# Only want to commit docs when building pushes on master &
# this doesn't have the built-in branch protection like commit-changes
if [ "$TRAVIS_EVENT_TYPE" == "push" ] && \
Expand All @@ -52,7 +52,7 @@ after_success:
then
# Generate docs
npm run gendocs
# Set up git env
git config --global user.email "$GH_USER_EMAIL"
git config --global user.name "$GH_USER_NAME"
Expand Down Expand Up @@ -88,12 +88,13 @@ deploy:
on:
tags: true
repo: MithrilJS/mithril.js

- provider: npm
skip_cleanup: true
email: npm@patcavit.com
email: me@isiahmeadows.com
api_key:
secure: ADElvD1oxn9GfEG7dDOggX96b36A/cGEybovAc0221CCKzv5kWCavMrtxneiJYI6N/n24abSlbM90vMfU84FEzH0Ev28dGVokRP4ad6VRkISszKlYVEP8Lds4QxfKh78jZlUxmxM0B3vmQ1kYJbTBqp3ICtaJ5ptEQHWhrLtxnc=
secure: "uPLbeJTalA/b38srb1VuWnD3eOgeKTkXf8VVUasUXIqc2xub4DSkFm1IVKSVd/rzP7EeO7+gRUs2UteNKlpZJl226IS5mFPSVtC7ViW46WSpYT0wlMsc7hrubMBGTx3/XYpPwtmMlTIGs5ICT7YkGAuju/6i79LDAB+gbnEY8Bc="
on:
tags: true
repo: MithrilJS/mithril.js
condition: "$TRAVIS_TAG != *-*"
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww

## What is Mithril?

A modern client-side Javascript framework for building Single Page Applications. It's small (<!-- size -->8.92 KB<!-- /size --> gzipped), fast and provides routing and XHR utilities out of the box.
A modern client-side Javascript framework for building Single Page Applications. It's small (<!-- size -->8.93 KB<!-- /size --> gzipped), fast and provides routing and XHR utilities out of the box.

Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍.

Expand All @@ -33,9 +33,8 @@ Browsers all the way back to IE9 are supported, no polyfills required 👌.
```

### npm

```bash
$ npm install mithril
$ npm install mithril --save
```

The ["Getting started" guide](https://mithril.js.org/#getting-started) is a good place to start learning how to use mithril.
Expand Down
196 changes: 96 additions & 100 deletions bundler/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,113 +17,109 @@ function parse(file) {

var error
function run(input, output) {
try {
var modules = {}
var bindings = {}
var declaration = /^\s*(?:var|let|const|function)[\t ]+([\w_$]+)/gm
var include = /(?:((?:var|let|const|,|)[\t ]*)([\w_$\.\[\]"'`]+)(\s*=\s*))?require\(([^\)]+)\)(\s*[`\.\(\[])?/gm
var uuid = 0
var process = function(filepath, data) {
data.replace(declaration, function(match, binding) {bindings[binding] = 0})

return data.replace(include, function(match, def, variable, eq, dep, rest) {
var filename = new Function("return " + dep).call(), pre = ""

def = def || "", variable = variable || "", eq = eq || "", rest = rest || ""
if (def[0] === ",") def = "\nvar ", pre = "\n"
var dependency = resolve(filepath, filename)
var localUUID = uuid // global uuid can update from nested `process` call, ensure same id is used on declaration and consumption
var code = process(dependency, pre + (modules[dependency] == null ? exportCode(filename, dependency, def, variable, eq, rest, localUUID) : def + variable + eq + modules[dependency]))
modules[dependency] = rest ? "_" + localUUID : variable
uuid++
return code + rest
})
var modules = {}
var bindings = {}
var declaration = /^\s*(?:var|let|const|function)[\t ]+([\w_$]+)/gm
var include = /(?:((?:var|let|const|,|)[\t ]*)([\w_$\.\[\]"'`]+)(\s*=\s*))?require\(([^\)]+)\)(\s*[`\.\(\[])?/gm
var uuid = 0
var process = function(filepath, data) {
data.replace(declaration, function(match, binding) {bindings[binding] = 0})

return data.replace(include, function(match, def, variable, eq, dep, rest) {
var filename = new Function("return " + dep).call(), pre = ""

def = def || "", variable = variable || "", eq = eq || "", rest = rest || ""
if (def[0] === ",") def = "\nvar ", pre = "\n"
var dependency = resolve(filepath, filename)
var localUUID = uuid // global uuid can update from nested `process` call, ensure same id is used on declaration and consumption
var code = process(dependency, pre + (modules[dependency] == null ? exportCode(filename, dependency, def, variable, eq, rest, localUUID) : def + variable + eq + modules[dependency]))
modules[dependency] = rest ? "_" + localUUID : variable
uuid++
return code + rest
})
}

var resolve = function(filepath, filename) {
if (filename[0] !== ".") {
// resolve as npm dependency
var packagePath = "./node_modules/" + filename + "/package.json"
var meta = isFile(packagePath) ? parse(packagePath) : {}
var main = "./node_modules/" + filename + "/" + (meta.main || filename + ".js")
return path.resolve(isFile(main) ? main : "./node_modules/" + filename + "/index.js")
}

var resolve = function(filepath, filename) {
if (filename[0] !== ".") {
// resolve as npm dependency
var packagePath = "./node_modules/" + filename + "/package.json"
var meta = isFile(packagePath) ? parse(packagePath) : {}
var main = "./node_modules/" + filename + "/" + (meta.main || filename + ".js")
return path.resolve(isFile(main) ? main : "./node_modules/" + filename + "/index.js")
}
else {
// resolve as local dependency
return path.resolve(path.dirname(filepath), filename + ".js")
}
else {
// resolve as local dependency
return path.resolve(path.dirname(filepath), filename + ".js")
}

var exportCode = function(filename, filepath, def, variable, eq, rest, uuid) {
var code = read(filepath)
// if there's a syntax error, report w/ proper stack trace
try {new Function(code)} catch (e) {
proc.exec("node " + filepath, function(e) {
if (e !== null && e.message !== error) {
error = e.message
console.log("\x1b[31m" + e.message + "\x1b[0m")
}
})
}

// disambiguate collisions
var ignored = {}
code.replace(include, function(match, def, variable, eq, dep) {
var filename = new Function("return " + dep).call()
var binding = modules[resolve(filepath, filename)]
if (binding != null) ignored[binding] = true
})
if (code.match(new RegExp("module\\.exports\\s*=\\s*" + variable + "\s*$", "m"))) ignored[variable] = true
for (var binding in bindings) {
if (!ignored[binding]) {
var before = code
code = code.replace(new RegExp("(\\b)" + binding + "\\b", "g"), binding + bindings[binding])
if (before !== code) bindings[binding]++
}

var exportCode = function(filename, filepath, def, variable, eq, rest, uuid) {
var code = read(filepath)
// if there's a syntax error, report w/ proper stack trace
try {new Function(code)} catch (e) {
proc.exec("node " + filepath, function(e) {
if (e !== null && e.message !== error) {
error = e.message
console.log("\x1b[31m" + e.message + "\x1b[0m")
}
}

// fix strings that got mangled by collision disambiguation
var string = /(["'])((?:\\\1|.)*?)(\1)/g
var candidates = Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|")
code = code.replace(string, function(match, open, data, close) {
var variables = new RegExp(Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|"), "g")
var fixed = data.replace(variables, function(match) {
return match.replace(/\d+$/, "")
})
return open + fixed + close
})

//fix props
var props = new RegExp("(\\.\\s*)(" + candidates + ")|([\\{,]\\s*)(" + candidates + ")(\\s*:)", "gm")
code = code.replace(props, function(match, dot, a, pre, b, post) {
if (dot) return dot + a.replace(/\d+$/, "")
else return pre + b.replace(/\d+$/, "") + post
})

return code
.replace(/("|')use strict\1;?/gm, "") // remove extraneous "use strict"
.replace(/module\.exports\s*=\s*/gm, rest ? "var _" + uuid + eq : def + (rest ? "_" : "") + variable + eq) // export
+ (rest ? "\n" + def + variable + eq + "_" + uuid : "") // if `rest` is truthy, it means the expression is fluent or higher-order (e.g. require(path).foo or require(path)(foo)
}
var versionTag = "bleeding-edge"
var packageFile = __dirname + "/../package.json"
var code = process(path.resolve(input), read(input))
.replace(/^\s*((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)(\2)(?=[\s]+(\w)|;|$)/gm, "") // remove assignments to self
.replace(/;+(\r|\n|$)/g, ";$1") // remove redundant semicolons
.replace(/(\r|\n)+/g, "\n").replace(/(\r|\n)$/, "") // remove multiline breaks
.replace(versionTag, isFile(packageFile) ? parse(packageFile).version : versionTag) // set version

code = ";(function() {\n" + code + "\n}());"

if (!isFile(output) || code !== read(output)) {
//try {new Function(code); console.log("build completed at " + new Date())} catch (e) {}
error = null
fs.writeFileSync(output, code, "utf8")

// disambiguate collisions
var ignored = {}
code.replace(include, function(match, def, variable, eq, dep) {
var filename = new Function("return " + dep).call()
var binding = modules[resolve(filepath, filename)]
if (binding != null) ignored[binding] = true
})
if (code.match(new RegExp("module\\.exports\\s*=\\s*" + variable + "\s*$", "m"))) ignored[variable] = true
for (var binding in bindings) {
if (!ignored[binding]) {
var before = code
code = code.replace(new RegExp("(\\b)" + binding + "\\b", "g"), binding + bindings[binding])
if (before !== code) bindings[binding]++
}
}

// fix strings that got mangled by collision disambiguation
var string = /(["'])((?:\\\1|.)*?)(\1)/g
var candidates = Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|")
code = code.replace(string, function(match, open, data, close) {
var variables = new RegExp(Object.keys(bindings).map(function(binding) {return binding + (bindings[binding] - 1)}).join("|"), "g")
var fixed = data.replace(variables, function(match) {
return match.replace(/\d+$/, "")
})
return open + fixed + close
})

//fix props
var props = new RegExp("((?:[^:]\\/\\/.*)?\\.\\s*)(" + candidates + ")|([\\{,]\\s*)(" + candidates + ")(\\s*:)", "gm")
code = code.replace(props, function(match, dot, a, pre, b, post) {
if (dot && dot.indexOf("//") === 1) return match // Don't do anything because dot was matched in a comment
else if (dot) return dot + a.replace(/\d+$/, "")
else return pre + b.replace(/\d+$/, "") + post
})

return code
.replace(/("|')use strict\1;?/gm, "") // remove extraneous "use strict"
.replace(/module\.exports\s*=\s*/gm, rest ? "var _" + uuid + eq : def + (rest ? "_" : "") + variable + eq) // export
+ (rest ? "\n" + def + variable + eq + "_" + uuid : "") // if `rest` is truthy, it means the expression is fluent or higher-order (e.g. require(path).foo or require(path)(foo)
}
catch (e) {
console.error(e.message)

var versionTag = "bleeding-edge"
var packageFile = __dirname + "/../package.json"
var code = process(path.resolve(input), read(input))
.replace(/^\s*((?:var|let|const|)[\t ]*)([\w_$\.]+)(\s*=\s*)(\2)(?=[\s]+(\w)|;|$)/gm, "") // remove assignments to self
.replace(/;+(\r|\n|$)/g, ";$1") // remove redundant semicolons
.replace(/(\r|\n)+/g, "\n").replace(/(\r|\n)$/, "") // remove multiline breaks
.replace(versionTag, isFile(packageFile) ? parse(packageFile).version : versionTag) // set version

code = ";(function() {\n" + code + "\n}());"

if (!isFile(output) || code !== read(output)) {
//try {new Function(code); console.log("build completed at " + new Date())} catch (e) {}
error = null
fs.writeFileSync(output, code, "utf8")
}
}

Expand Down
48 changes: 27 additions & 21 deletions bundler/cli.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"use strict"

var fs = require("fs");
var zlib = require("zlib")

var bundle = require("./bundle")
var minify = require("./minify")

var aliases = {o: "output", m: "minify", w: "watch", a: "aggressive", s: "save"}
var aliases = {o: "output", m: "minify", w: "watch", s: "save"}
var params = {}
var args = process.argv.slice(2), command = null
for (var i = 0; i < args.length; i++) {
Expand All @@ -24,26 +25,31 @@ function add(value) {
command = null
}

function format(n) {
return n.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")
}

bundle(params.input, params.output, {watch: params.watch})
if (params.minify) {
minify(params.output, params.output, {watch: params.watch, advanced: params.aggressive}, function(stats) {
function format(n) {
return n.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")
}

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)")

if (params.save) {
var readme = fs.readFileSync("./README.md", "utf8")
var kb = stats.compressedGzipSize / 1000

fs.writeFileSync("./README.md",
readme.replace(
/(<!-- size -->)(.+?)(<!-- \/size -->)/,
"$1" + (kb % 1 ? kb.toFixed(2) : kb) + " KB$3"
)
// mFiles = { original: String(mithril.js), compressed: String(mithril.min.js) }
var mFiles = minify(params.output, {watch: params.watch})
var originalSize = mFiles.original.length
var compressedSize = mFiles.compressed.length
var originalGzipSize = zlib.gzipSync(mFiles.original).byteLength
var compressedGzipSize = zlib.gzipSync(mFiles.compressed).byteLength

console.log("Original size: " + format(originalGzipSize) + " bytes gzipped (" + format(originalSize) + " bytes uncompressed)")
console.log("Compiled size: " + format(compressedGzipSize) + " bytes gzipped (" + format(compressedSize) + " bytes uncompressed)")

if (params.save) {
var readme = fs.readFileSync("./README.md", "utf8")
var kb = compressedGzipSize / 1000

fs.writeFileSync("./README.md",
readme.replace(
/(<!-- size -->)(.+?)(<!-- \/size -->)/,
"$1" + (kb % 1 ? kb.toFixed(2) : kb) + " KB$3"
)
}
})
}
)
}
}
Loading

0 comments on commit f84ac07

Please sign in to comment.