Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this allows compiling bundles programmatically, using strings rather than files as entry points the implementation is a little convoluted (cf. inline comments), but works well with faucet's intentional constraints - see rollup/rollup#2509 (comment) for details
- Loading branch information
Showing
9 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/test/unit/expected |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"use strict"; | ||
|
||
let path = require("path"); | ||
|
||
let PREFIX = "diskless:"; | ||
|
||
// Rollup plugin for virtual modules | ||
// `referenceDir` is used for relative imports from diskless modules | ||
// `resolver` is the Rollup plugin responsible for import paths | ||
// `modules` maps file names to source code | ||
module.exports = (referenceDir, resolver, modules = new Map(), prefix = PREFIX) => ({ | ||
name: "diskless", | ||
resolveId(importee, importer) { | ||
if(importer && importer.startsWith(prefix)) { | ||
let virtual = path.resolve(referenceDir, importer); | ||
// this is pretty hacky, but necessary because Rollup doesn't | ||
// support combining different plugins' `#resolveId` | ||
return resolver.resolveId(importee, virtual); | ||
} | ||
return importee.startsWith(prefix) ? importee : null; | ||
}, | ||
load(id) { | ||
if(!id.startsWith(prefix)) { | ||
return null; | ||
} | ||
|
||
let filename = id.substr(prefix.length); | ||
let source = modules.get(filename); | ||
if(source === undefined) { | ||
throw new Error(`missing diskless module: ${filename}`); | ||
} | ||
return source; | ||
}, | ||
register(filename, source) { | ||
modules.set(filename, source); | ||
}, | ||
deregister(filename) { | ||
return modules.delete(filename); | ||
}, | ||
get prefix() { | ||
return prefix; | ||
} | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
"use strict"; | ||
|
||
let BasicBundle = require("./basic"); | ||
let diskless = require("./diskless"); | ||
let crypto = require("crypto"); | ||
|
||
exports.VirtualBundle = class VirtualBundle extends BasicBundle { | ||
constructor(referenceDir, config, { browsers }) { | ||
super(config, { browsers }); | ||
// inject diskless plugin, initializing it with existing resolver | ||
// this is pretty convoluted, but necessary due to Rollup limitations | ||
// (see diskless internals for details) | ||
let { plugins } = this._config.readConfig; | ||
let resolver = plugins.find(plugin => plugin.name === "node-resolve"); | ||
let plugin = diskless(referenceDir, resolver); | ||
plugins.unshift(plugin); | ||
this.diskless = plugin; | ||
} | ||
|
||
compile(source) { | ||
let { diskless } = this; | ||
// NB: unique-ish ID avoids potential race condition for concurrent | ||
// access with identical sources | ||
// TODO: does file extension matter? | ||
let id = generateHash(new Date().getTime() + source); | ||
let filename = `entry_point_${id}.js`; | ||
|
||
diskless.register(filename, source); | ||
let cleanup = () => void diskless.deregister(filename); | ||
|
||
return super.compile(diskless.prefix + filename). | ||
then(res => { | ||
cleanup(); | ||
return res; | ||
}). | ||
catch(err => { | ||
cleanup(); | ||
throw err; | ||
}); | ||
} | ||
}; | ||
|
||
// XXX: duplicates private faucet-core's fingerprinting | ||
function generateHash(str) { | ||
let hash = crypto.createHash("md5"); | ||
hash.update(str); | ||
return hash.digest("hex"); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
(function () { | ||
'use strict'; | ||
|
||
if(typeof global === "undefined" && typeof window !== "undefined") { | ||
window.global = window; | ||
} | ||
|
||
var UTIL = "UTIL"; | ||
|
||
console.log(UTIL); | ||
|
||
}()); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(function () { | ||
'use strict'; | ||
|
||
if(typeof global === "undefined" && typeof window !== "undefined") { | ||
window.global = window; | ||
} | ||
|
||
var UTIL = "UTIL"; | ||
|
||
var MYLIB = "MY-LIB"; | ||
|
||
console.log(UTIL + MYLIB); | ||
|
||
}()); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
'use strict'; | ||
|
||
if(typeof global === "undefined" && typeof window !== "undefined") { | ||
window.global = window; | ||
} | ||
|
||
var UTIL = "UTIL"; | ||
|
||
var MYLIB = "MY-LIB"; | ||
|
||
function createElement(tag, params, ...children) { | ||
return `<${tag} ${JSON.stringify(params)}>${JSON.stringify(children)}</${tag}>`; | ||
} | ||
|
||
function Button({ | ||
type, | ||
label | ||
}) { | ||
return createElement("button", { | ||
type: type | ||
}, label); | ||
} | ||
function List(_, ...children) { | ||
return createElement("ul", null, children.map(item => createElement("li", null, item))); | ||
} | ||
|
||
console.log(createElement(List, null, createElement(Button, { | ||
label: UTIL | ||
}), createElement(Button, { | ||
type: "reset", | ||
label: MYLIB | ||
}))); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* global describe, it */ | ||
"use strict"; | ||
|
||
let { FIXTURES_DIR } = require("./util"); | ||
let { VirtualBundle } = require("../../lib/bundle/virtual"); | ||
let fs = require("fs"); | ||
let path = require("path"); | ||
let assert = require("assert"); | ||
|
||
let assertSame = assert.strictEqual; | ||
|
||
let DEFAULT_OPTIONS = { | ||
browsers: {} | ||
}; | ||
|
||
describe("virtual bundle", _ => { | ||
it("should bundle JavaScript from a source string", async () => { | ||
let bundle = new VirtualBundle(FIXTURES_DIR, null, DEFAULT_OPTIONS); | ||
|
||
let res = await bundle.compile(` | ||
import UTIL from "./src/util"; | ||
console.log(UTIL); | ||
`); | ||
assertSame(res.error, undefined); | ||
assertSame(res.code, expectedBundle("virtual_bundle_js1.js")); | ||
|
||
res = await bundle.compile(` | ||
import UTIL from "./src/util"; | ||
import MYLIB from "my-lib"; | ||
console.log(UTIL + MYLIB); | ||
`); | ||
assertSame(res.error, undefined); | ||
assertSame(res.code, expectedBundle("virtual_bundle_js2.js")); | ||
}); | ||
|
||
it("should support JSX", async () => { | ||
let bundle = new VirtualBundle(FIXTURES_DIR, { | ||
format: "CommonJS", | ||
jsx: { pragma: "createElement" } | ||
}, DEFAULT_OPTIONS); | ||
|
||
let { code, error } = await bundle.compile(` | ||
import UTIL from "./src/util"; | ||
import MYLIB from "my-lib"; | ||
import { Button, List } from "my-lib/components"; | ||
import createElement from "my-lib/elements"; | ||
console.log(<List> | ||
<Button label={UTIL} /> | ||
<Button type="reset" label={MYLIB} /> | ||
</List>); | ||
`); | ||
assertSame(error, undefined); | ||
assertSame(code, expectedBundle("virtual_bundle_jsx.js")); | ||
}); | ||
}); | ||
|
||
function expectedBundle(filename) { | ||
return fs.readFileSync(path.resolve(__dirname, "expected", filename), "utf8"); | ||
} |