Implement Automatic Proxy Between the Host JS and the Prepack JS Environment
#644 建立於 2017年5月15日
描述
While writing #397 most of what I wrote was sloppy proxying code between the host (Node) JS environment and the Prepack JS environment. 1:1. It would be nice to have an automatic way of doing that.
Proxy
The use case for Proxy in the JS spec is to be able to put up a membrane between two environments. We can write a two-way bridging model between the two environments. Whenever we expose an unseen object reference from the host to JS we wrap it in a "proxy object value" and store that in a weak map for reuse. Similarly, when we call into the JS host we unwrap such objects. If it is a new object value from the JS side, we wrap it in a host Proxy object on the native JS side. Abstract values are not allowed on this level. Prepacked code can introspect values using __isAbstract and provide a fallback in those cases.
This lets us call seamlessly between the two environments.
Now we can expose new functionality such as requiring arbitary Node modules from within a Prepacked file. This allows custom Prepack helpers to be written in user space code rather than having to expose anything about the internal APIs and implementation details.
"Plugin" API
if (typeof __prepackRequire === 'function') {
let fs = __prepackRequire('fs');
fs.writeFileSync(...);
}
We have requests for some plugin API for various custom static analysis use cases. One example, is being able to generate stand-alone CSS files from the content of a JS object and replace the JS object with a string to CSS class name.
This might be the only plugin mechanism we really need. Now a JS library can just execute arbitrary code inside their Prepacked helpers.
function generateCSS(style) {
if (typeof __prepackRequire === 'function') {
let fs = __prepackRequire('fs');
let process = __prepackRequire('process');
let options = parseOptions(process.argv);
let className = 'AutoCSS' + Math.random();
let cssText = `.${className} { ${generateStyle(style)} }`;
fs.writeFileSync(options.cssOutputFile, cssText, 'utf8');
return className;
} else {
throw new Error('All CSS needs to be statically generated.');
}
}
let MyOtherModule = require('MyOtherModule');
let div = document.createElement('div');
div.className = generateCSS({
position: 'absolute',
width: '100%',
border: `${MyOtherModule.borderWidth}px solid ${MyOtherModule.borderColor}`,
});
-> JS file:
let div = document.createElement('div');
div.className = 'AutoCSS123';
CSS file:
.AutoCSS123 {
position: absolute;
width: 100%;
border: 45px solid #6789AB;
}
We might need some security mechanism to prevent abuse. E.g. only allowing particular modules to be require or just a global option allowArbitraryExecution.