mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-08-16 18:10:33 +03:00
Refactor the public API in a similar style to Babel API (#469)
* Refactor the public API This refactors the public Node API to mimic the [Babel API](http://babeljs.io/docs/usage/api/). This is a bit more idiomatic than "run CLI" or instantiate the full serializer object. I'm passing a single options object instead of individual arguments. This is a bit more managable as the option list grows. The prepack-node file is what is exposed in Node which has a file system API. Both synchronous and asynchronous forms. prepack-standalone is a module for environments without access to the file system such as browsers. I configure this to be exposed by default for such environments. That way we can also use this in the webpack build so that our own repl on the website can just use this public API. * Throw an error when serialization fails This lets any compiler flow to terminate properly by default but the error can safely be ignored if we've already printed error messages for it such as in the CLI. Turn internalDebug error messages off by default but allow it to be configured. * Added missing realm options Not yet exposed in the cli but available through the API.
This commit is contained in:
parent
cfbf667c21
commit
111af14f61
@ -20,7 +20,8 @@
|
||||
"prepack": "bin/prepack.js",
|
||||
"prepack-repl": "bin/prepack-repl.js"
|
||||
},
|
||||
"main": "lib/prepack.js",
|
||||
"main": "lib/prepack-node.js",
|
||||
"browser": "lib/prepack-standalone.js",
|
||||
"scripts": {
|
||||
"build": "babel src --out-dir lib --source-maps && npm run build-bundle",
|
||||
"build-bundle": "webpack",
|
||||
|
71
src/options.js
Normal file
71
src/options.js
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
|
||||
import type { RealmOptions } from "./types";
|
||||
import type { SerializerOptions } from "./serializer/types";
|
||||
|
||||
export type Options = {
|
||||
filename?: string,
|
||||
inputSourceMapFilename?: string,
|
||||
sourceMaps?: boolean,
|
||||
compatibility?: "browser" | "jsc-600-1-4-17",
|
||||
mathRandomSeed?: string,
|
||||
speculate?: boolean,
|
||||
trace?: boolean,
|
||||
debugNames?: boolean,
|
||||
singlePass?: boolean,
|
||||
logStatistics?: boolean,
|
||||
logModules?: boolean,
|
||||
delayUnsupportedRequires?: boolean,
|
||||
internalDebug?: boolean,
|
||||
uniqueSuffix?: string,
|
||||
timeout?: number,
|
||||
strictlyMonotonicDateNow?: boolean,
|
||||
};
|
||||
|
||||
export function getRealmOptions({
|
||||
compatibility = "browser",
|
||||
mathRandomSeed,
|
||||
debugNames = false,
|
||||
uniqueSuffix,
|
||||
timeout,
|
||||
strictlyMonotonicDateNow
|
||||
}: Options): RealmOptions {
|
||||
return {
|
||||
partial: true,
|
||||
compatibility,
|
||||
mathRandomSeed,
|
||||
debugNames,
|
||||
uniqueSuffix,
|
||||
timeout,
|
||||
strictlyMonotonicDateNow,
|
||||
};
|
||||
}
|
||||
|
||||
export function getSerializerOptions({
|
||||
speculate = false,
|
||||
trace = false,
|
||||
singlePass = false,
|
||||
logStatistics = false,
|
||||
logModules = false,
|
||||
delayUnsupportedRequires = false,
|
||||
internalDebug = false
|
||||
}: Options): SerializerOptions {
|
||||
return {
|
||||
initializeMoreModules: speculate,
|
||||
trace,
|
||||
singlePass,
|
||||
logStatistics,
|
||||
logModules,
|
||||
delayUnsupportedRequires,
|
||||
internalDebug,
|
||||
};
|
||||
}
|
@ -9,7 +9,8 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
import { run } from "./prepack.js";
|
||||
import { prepackFileSync, InitializationError } from "./prepack-node.js";
|
||||
import fs from "fs";
|
||||
|
||||
let args = Array.from(process.argv);
|
||||
args.splice(0, 2);
|
||||
@ -17,8 +18,8 @@ let inputFilename;
|
||||
let outputFilename;
|
||||
let compatibility;
|
||||
let mathRandomSeed;
|
||||
let inputMap;
|
||||
let ouputMap;
|
||||
let inputSourceMap;
|
||||
let outputSourceMap;
|
||||
let flags = {
|
||||
speculate: false,
|
||||
trace: false,
|
||||
@ -27,6 +28,7 @@ let flags = {
|
||||
logStatistics: false,
|
||||
logModules: false,
|
||||
delayUnsupportedRequires: false,
|
||||
internalDebug: false,
|
||||
};
|
||||
while (args.length) {
|
||||
let arg = args[0]; args.shift();
|
||||
@ -52,10 +54,10 @@ while (args.length) {
|
||||
mathRandomSeed = args[0]; args.shift();
|
||||
break;
|
||||
case "srcmapIn":
|
||||
inputMap = args[0]; args.shift();
|
||||
inputSourceMap = args[0]; args.shift();
|
||||
break;
|
||||
case "srcmapOut":
|
||||
ouputMap = args[0]; args.shift();
|
||||
outputSourceMap = args[0]; args.shift();
|
||||
break;
|
||||
case "help":
|
||||
console.log("Usage: prepack.js [ --out output.js ] [ --compatibility jsc ] [ --mathRandomSeed seedvalue ] [ --srcmapIn inputMap ] [ --srcmapOut outputMap ] [ --speculate ] [ --trace ] [ -- | input.js ] [ --singlePass ] [ --debugNames ]");
|
||||
@ -70,9 +72,44 @@ while (args.length) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!inputFilename) {
|
||||
console.error("Missing input file.");
|
||||
process.exit(1);
|
||||
} else {
|
||||
run(inputFilename, compatibility, mathRandomSeed, outputFilename, inputMap, ouputMap, flags.speculate, flags.trace, flags.debugNames, flags.singlePass, flags.logStatistics, flags.logModules, flags.delayUnsupportedRequires);
|
||||
try {
|
||||
let serialized = prepackFileSync(inputFilename, {
|
||||
compatibility,
|
||||
mathRandomSeed,
|
||||
inputSourceMapFilename: inputSourceMap,
|
||||
sourceMaps: !!outputSourceMap,
|
||||
...flags
|
||||
});
|
||||
|
||||
let code = serialized.code;
|
||||
|
||||
if (code.length >= 1000 || outputFilename) {
|
||||
let filename = outputFilename || (inputFilename + "-processed.js");
|
||||
console.log(`Prepacked source code written to ${filename}.`);
|
||||
fs.writeFileSync(filename, code);
|
||||
}
|
||||
|
||||
if (code.length <= 1000 && !outputFilename) {
|
||||
console.log("+++++++++++++++++ Prepacked source code");
|
||||
console.log(code);
|
||||
console.log("=================");
|
||||
}
|
||||
|
||||
if (outputSourceMap) {
|
||||
fs.writeFileSync(outputSourceMap, serialized.map || "");
|
||||
}
|
||||
} catch (x) {
|
||||
if (x instanceof InitializationError) {
|
||||
// Ignore InitializationError since they have already logged
|
||||
// their errors to the console, but exit with an error code.
|
||||
process.exit(1);
|
||||
}
|
||||
// For any other type of error, rethrow.
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
67
src/prepack-node.js
Normal file
67
src/prepack-node.js
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import Serializer from "./serializer/index.js";
|
||||
import fs from "fs";
|
||||
import { getRealmOptions, getSerializerOptions } from "./options";
|
||||
import { InitializationError } from "./prepack-standalone";
|
||||
|
||||
import type { Options } from "./options";
|
||||
|
||||
export * from "./prepack-standalone";
|
||||
|
||||
export function prepackFile(filename: string, options: Options = {}, callback: Function) {
|
||||
let sourceMapFilename = options.inputSourceMapFilename || (filename + ".map");
|
||||
fs.readFile(filename, "utf8", function(fileErr, code) {
|
||||
if (fileErr) {
|
||||
callback(fileErr);
|
||||
return;
|
||||
}
|
||||
fs.readFile(sourceMapFilename, "utf8", function(mapErr, sourceMap) {
|
||||
if (mapErr) {
|
||||
console.log(`No sourcemap found at ${sourceMapFilename}.`);
|
||||
sourceMap = "";
|
||||
}
|
||||
let serialized;
|
||||
try {
|
||||
serialized = new Serializer(
|
||||
getRealmOptions(options),
|
||||
getSerializerOptions(options),
|
||||
).init(filename, code, sourceMap, options.sourceMaps);
|
||||
if (!serialized) {
|
||||
throw new InitializationError();
|
||||
}
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
callback(null, serialized);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function prepackFileSync(filename: string, options: Options = {}) {
|
||||
let code = fs.readFileSync(filename, "utf8");
|
||||
let sourceMap = "";
|
||||
let sourceMapFilename = options.inputSourceMapFilename || (filename + ".map");
|
||||
try {
|
||||
sourceMap = fs.readFileSync(sourceMapFilename, "utf8");
|
||||
} catch (_e) {
|
||||
console.log(`No sourcemap found at ${sourceMapFilename}.`);
|
||||
}
|
||||
let serialized = new Serializer(
|
||||
getRealmOptions(options),
|
||||
getSerializerOptions(options),
|
||||
).init(filename, code, sourceMap, options.sourceMaps);
|
||||
if (!serialized) {
|
||||
throw new InitializationError();
|
||||
}
|
||||
return serialized;
|
||||
}
|
59
src/prepack-standalone.js
Normal file
59
src/prepack-standalone.js
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import Serializer from "./serializer/index.js";
|
||||
import * as t from "babel-types";
|
||||
import { getRealmOptions, getSerializerOptions } from "./options";
|
||||
|
||||
import type { Options } from "./options";
|
||||
import type { BabelNodeFile, BabelNodeProgram } from "babel-types";
|
||||
|
||||
// This should just be a class but Babel classes doesn't work with
|
||||
// built-in super classes.
|
||||
export function InitializationError() {
|
||||
let self = new Error("An error occurred while prepacking. See the error logs.");
|
||||
Object.setPrototypeOf(self, InitializationError.prototype);
|
||||
return self;
|
||||
}
|
||||
Object.setPrototypeOf(InitializationError, Error);
|
||||
Object.setPrototypeOf(InitializationError.prototype, Error.prototype);
|
||||
|
||||
|
||||
export function prepack(code: string, options: Options = {}) {
|
||||
let filename = options.filename || 'unknown';
|
||||
let serialized = new Serializer(
|
||||
getRealmOptions(options),
|
||||
getSerializerOptions(options),
|
||||
).init(filename, code, "", false);
|
||||
if (!serialized) {
|
||||
throw new InitializationError();
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
export function prepackFromAst(ast: BabelNodeFile | BabelNodeProgram, code: string, options: Options = {}) {
|
||||
if (ast && ast.type === "Program") {
|
||||
ast = t.file(ast, [], []);
|
||||
} else if (!ast || ast.type !== "File") {
|
||||
throw new Error("Not a valid ast?");
|
||||
}
|
||||
|
||||
// TODO: Expose an option to wire an already parsed ast all the way through
|
||||
// to the execution environment. For now, we just reparse.
|
||||
|
||||
let serialized = new Serializer(
|
||||
getRealmOptions(options),
|
||||
getSerializerOptions(options),
|
||||
).init("", code, "", options.sourceMaps);
|
||||
if (!serialized) {
|
||||
throw new InitializationError();
|
||||
}
|
||||
return serialized;
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* @flow */
|
||||
import Serializer from "./serializer/index.js";
|
||||
import invariant from "./invariant.js";
|
||||
let fs = require("fs");
|
||||
|
||||
function run_internal(
|
||||
name: string,
|
||||
raw: string,
|
||||
map: string = "",
|
||||
compatibility?: "browser" | "jsc-600-1-4-17" = "browser",
|
||||
mathRandomSeed: void | string,
|
||||
outputFilename?: string,
|
||||
outputMap?: string,
|
||||
speculate: boolean = false,
|
||||
trace: boolean = false,
|
||||
debugNames: boolean = false,
|
||||
singlePass: boolean = false,
|
||||
logStatistics: boolean = false,
|
||||
logModules: boolean = false,
|
||||
delayUnsupportedRequires: boolean = false) {
|
||||
let serialized =
|
||||
new Serializer(
|
||||
{ partial: true, compatibility, mathRandomSeed, debugNames },
|
||||
{ initializeMoreModules: speculate, internalDebug: true, trace, singlePass, logStatistics, logModules, delayUnsupportedRequires })
|
||||
.init(name, raw, map, outputMap !== undefined);
|
||||
if (!serialized) {
|
||||
process.exit(1);
|
||||
invariant(false);
|
||||
}
|
||||
let code = serialized.code;
|
||||
|
||||
if (code.length >= 1000 || outputFilename) {
|
||||
let filename = outputFilename || (name + "-processed.js");
|
||||
console.log(`Prepacked source code written to ${filename}.`);
|
||||
fs.writeFileSync(filename, code);
|
||||
}
|
||||
|
||||
if (code.length <= 1000 && !outputFilename) {
|
||||
console.log("+++++++++++++++++ Prepacked source code");
|
||||
console.log(code);
|
||||
console.log("=================");
|
||||
}
|
||||
|
||||
if (outputMap) {
|
||||
fs.writeFileSync(outputMap, map);
|
||||
}
|
||||
}
|
||||
|
||||
export function run(
|
||||
inFn: string,
|
||||
compat?: "browser" | "jsc-600-1-4-17" = "browser",
|
||||
mathRandSeed: void | string,
|
||||
outFn?: string,
|
||||
inputMap?: string,
|
||||
outMap?: string,
|
||||
speculateOpt?: boolean,
|
||||
trace?: boolean,
|
||||
debugNames?: boolean,
|
||||
singlePass?: boolean,
|
||||
logStatistics?: boolean,
|
||||
logModules?: boolean,
|
||||
delayUnsupportedRequires?: boolean) {
|
||||
let input = fs.readFileSync(inFn, "utf8");
|
||||
let map = "";
|
||||
let mapFile = inputMap ? inputMap : inFn + ".map";
|
||||
try {
|
||||
map = fs.readFileSync(mapFile, "utf8");
|
||||
} catch (_e) {
|
||||
console.log(`No sourcemap found at ${mapFile}.`);
|
||||
}
|
||||
run_internal(inFn, input, map, compat, mathRandSeed, outFn, outMap, speculateOpt, trace, debugNames, singlePass, logStatistics, logModules, delayUnsupportedRequires);
|
||||
}
|
@ -11,11 +11,11 @@ const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const WebpackConfig = {
|
||||
entry: "./lib/serializer/index.js",
|
||||
entry: "./",
|
||||
output: {
|
||||
path: path.join(__dirname),
|
||||
filename: "prepack.min.js",
|
||||
library: 'prepack',
|
||||
library: 'Prepack',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
|
Loading…
Reference in New Issue
Block a user