mirror of
https://github.com/mdgriffith/elm-optimize-level-2.git
synced 2024-11-25 22:50:42 +03:00
reorganize things so its a little easier to follow.
This commit is contained in:
parent
aa550025d1
commit
c685817eaa
@ -4,7 +4,7 @@ import * as path from 'path';
|
||||
import { parseElm } from './parseElm';
|
||||
import ts from 'typescript';
|
||||
import { createCustomTypesTransformer } from './experiments/variantShapes';
|
||||
import { Mode } from './types';
|
||||
import { Mode, Transforms, ObjectUpdate } from './types';
|
||||
import {
|
||||
createFunctionInlineTransformer,
|
||||
InlineContext,
|
||||
@ -20,18 +20,13 @@ import { execSync } from 'child_process';
|
||||
import {
|
||||
createReplaceUtilsUpdateWithObjectSpread,
|
||||
convertFunctionExpressionsToArrowFuncs,
|
||||
NativeSpread,
|
||||
} from './experiments/modernizeJS';
|
||||
import { createRemoveUnusedLocalsTransform } from './experiments/removeUnusedLocals';
|
||||
|
||||
type TransformOptions = {
|
||||
prepack: boolean;
|
||||
};
|
||||
|
||||
export const compileAndTransform = async (
|
||||
dir: string,
|
||||
file: string,
|
||||
options?: TransformOptions
|
||||
options: Transforms
|
||||
): Promise<{}> => {
|
||||
// Compile examples in `testcases/*` folder as js
|
||||
// Run whatever transformations we want on them, saving steps as `elm.{transformation}.js`
|
||||
@ -71,25 +66,27 @@ export const compileAndTransform = async (
|
||||
Mode.Prod
|
||||
);
|
||||
|
||||
const transformations = removeDisabled([
|
||||
[options.variantShapes, normalizeVariantShapes],
|
||||
[
|
||||
options.inlineFunctions,
|
||||
createFunctionInlineTransformer(reportInlineTransformResult),
|
||||
],
|
||||
[
|
||||
options.listLiterals,
|
||||
createInlineListFromArrayTransformer(
|
||||
InlineMode.UsingLiteralObjects(Mode.Prod)
|
||||
),
|
||||
],
|
||||
includeObjectUpdate(options.objectUpdate),
|
||||
[options.arrowFns, convertFunctionExpressionsToArrowFuncs],
|
||||
[options.unusedValues, createRemoveUnusedLocalsTransform()],
|
||||
]);
|
||||
|
||||
const {
|
||||
transformed: [result],
|
||||
diagnostics,
|
||||
} = ts.transform(source, [
|
||||
normalizeVariantShapes,
|
||||
createFunctionInlineTransformer(reportInlineTransformResult),
|
||||
createInlineListFromArrayTransformer(
|
||||
InlineMode.UsingLiteralObjects(Mode.Prod)
|
||||
// InlineMode.UsingLiteralObjects(Mode.Prod)
|
||||
),
|
||||
createReplaceUtilsUpdateWithObjectSpread(
|
||||
NativeSpread.UseSpreadForUpdateAndOriginalRecord
|
||||
),
|
||||
|
||||
convertFunctionExpressionsToArrowFuncs,
|
||||
|
||||
// This is awesome work, but disabling it for now to make things run faster
|
||||
// createRemoveUnusedLocalsTransform(),
|
||||
]);
|
||||
} = ts.transform(source, transformations);
|
||||
|
||||
const printer = ts.createPrinter();
|
||||
|
||||
@ -106,16 +103,19 @@ export const compileAndTransform = async (
|
||||
|
||||
fs.writeFileSync(pathInOutput('elm.opt.js'), printer.printFile(initialJs));
|
||||
|
||||
if (options?.prepack) {
|
||||
// console.log('here');
|
||||
if (options.prepack) {
|
||||
const { code } = prepackFileSync([pathInOutput('elm.opt.transformed.js')], {
|
||||
debugNames: true,
|
||||
inlineExpressions: true,
|
||||
maxStackDepth: 1200, // that didn't help
|
||||
});
|
||||
// console.log('there', code.length);
|
||||
|
||||
fs.writeFileSync(pathInOutput('elm.opt.prepack.js'), code);
|
||||
await minify(
|
||||
pathInOutput('elm.opt.prepack.js'),
|
||||
pathInOutput('elm.opt.prepack.min.js')
|
||||
);
|
||||
gzip(pathInOutput('elm.opt.prepack.min.js'));
|
||||
}
|
||||
|
||||
await minify(pathInOutput('elm.opt.js'), pathInOutput('elm.opt.min.js'));
|
||||
@ -125,15 +125,28 @@ export const compileAndTransform = async (
|
||||
pathInOutput('elm.opt.transformed.min.js')
|
||||
);
|
||||
gzip(pathInOutput('elm.opt.transformed.min.js'));
|
||||
await minify(
|
||||
pathInOutput('elm.opt.prepack.js'),
|
||||
pathInOutput('elm.opt.prepack.min.js')
|
||||
);
|
||||
gzip(pathInOutput('elm.opt.prepack.min.js'));
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
function includeObjectUpdate(objectUpdate: ObjectUpdate | null): any {
|
||||
if (objectUpdate != null) {
|
||||
return [true, createReplaceUtilsUpdateWithObjectSpread(objectUpdate)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function removeDisabled(list: any[]) {
|
||||
let newList: any[] = [];
|
||||
list.forEach(item => {
|
||||
if (item != 0 && item[0]) {
|
||||
newList.push(item[1]);
|
||||
}
|
||||
});
|
||||
return newList;
|
||||
}
|
||||
|
||||
async function minify(inputFilename: string, outputFilename: string) {
|
||||
const compress = {
|
||||
toplevel: true,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import ts from 'typescript';
|
||||
import { ObjectUpdate } from './../types';
|
||||
|
||||
const copyWithSpread = `
|
||||
const _Utils_update = (oldRecord, updatedFields) => {
|
||||
@ -21,13 +22,8 @@ const extractBody = (sourceText: string): ts.Node => {
|
||||
return source.statements[0];
|
||||
};
|
||||
|
||||
export enum NativeSpread {
|
||||
UseSpreadForUpdateAndOriginalRecord = 'for_both',
|
||||
UseSpreadOnlyToMakeACopy = 'for_copy',
|
||||
}
|
||||
|
||||
export const createReplaceUtilsUpdateWithObjectSpread = (
|
||||
kind: NativeSpread
|
||||
kind: ObjectUpdate
|
||||
): ts.TransformerFactory<ts.SourceFile> => context => {
|
||||
return sourceFile => {
|
||||
const visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
|
||||
@ -37,9 +33,9 @@ export const createReplaceUtilsUpdateWithObjectSpread = (
|
||||
node.name?.text === '_Utils_update'
|
||||
) {
|
||||
switch (kind) {
|
||||
case NativeSpread.UseSpreadForUpdateAndOriginalRecord:
|
||||
case ObjectUpdate.UseSpreadForUpdateAndOriginalRecord:
|
||||
return extractBody(spreadForBoth);
|
||||
case NativeSpread.UseSpreadOnlyToMakeACopy:
|
||||
case ObjectUpdate.UseSpreadOnlyToMakeACopy:
|
||||
return extractBody(copyWithSpread);
|
||||
}
|
||||
}
|
||||
|
@ -5,259 +5,35 @@ Compiles all the test cases and runs them via webdriver to summarize the results
|
||||
|
||||
*/
|
||||
|
||||
import * as compile from './compile-testcases';
|
||||
import * as webdriver from 'selenium-webdriver';
|
||||
import * as chrome from 'selenium-webdriver/chrome';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { ObjectUpdate } from './types';
|
||||
import * as Reporting from './reporting';
|
||||
|
||||
const visitBenchmark = async (tag: string | null, file: string) => {
|
||||
let driver = new webdriver.Builder()
|
||||
.forBrowser('chrome')
|
||||
// .setChromeOptions(/* ... */)
|
||||
// .setFirefoxOptions(/* ... */)
|
||||
.build();
|
||||
|
||||
// docs for selenium:
|
||||
// https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
|
||||
let result = [];
|
||||
try {
|
||||
await driver.get('file://' + path.resolve(file));
|
||||
await driver.wait(webdriver.until.titleIs('done'), 480000);
|
||||
result = await driver.executeScript('return window.results;');
|
||||
} finally {
|
||||
await driver.quit();
|
||||
}
|
||||
return { tag: tag, browser: 'chrome', results: result };
|
||||
const defaultOptions = {
|
||||
prepack: true,
|
||||
variantShapes: true,
|
||||
inlineFunctions: true,
|
||||
listLiterals: true,
|
||||
arrowFns: true,
|
||||
objectUpdate: ObjectUpdate.UseSpreadOnlyToMakeACopy,
|
||||
unusedValues: false,
|
||||
};
|
||||
|
||||
export interface Stat {
|
||||
name: string;
|
||||
bytes: number;
|
||||
async function go() {
|
||||
const report = await Reporting.run([
|
||||
// { name: 'simple',
|
||||
// dir: 'testcases/simple',
|
||||
// elmFile: 'main',
|
||||
// options: defaultOptions,
|
||||
// },
|
||||
{
|
||||
name: 'bench',
|
||||
dir: 'testcases/bench',
|
||||
elmFile: 'Main.elm',
|
||||
options: defaultOptions,
|
||||
},
|
||||
]);
|
||||
|
||||
console.log(Reporting.markdown(await report));
|
||||
}
|
||||
|
||||
const assetSizeStats = (dir: string): Stat[] => {
|
||||
let stats: Stat[] = [];
|
||||
fs.readdir(dir, function(err, files) {
|
||||
if (err) {
|
||||
console.log('Error getting directory information.');
|
||||
} else {
|
||||
files.forEach(function(file) {
|
||||
const stat = fs.statSync(path.join(dir, file));
|
||||
stats.push({
|
||||
name: path.basename(file),
|
||||
bytes: stat.size,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return stats;
|
||||
};
|
||||
|
||||
const run = async function() {
|
||||
await compile.compileAndTransform('testcases/simple', 'Main.elm', {
|
||||
prepack: true,
|
||||
});
|
||||
await compile.compileAndTransform('testcases/bench', 'Main.elm', {
|
||||
prepack: true,
|
||||
});
|
||||
await compile.compileAndTransform('testcases/elm-markup', 'Run.elm', {
|
||||
prepack: true,
|
||||
});
|
||||
await compile.compileAndTransform('testcases/elm-obj-file', 'Run.elm', {
|
||||
prepack: true,
|
||||
});
|
||||
|
||||
const assets = {
|
||||
bench: assetSizeStats('testcases/bench/output'),
|
||||
simple: assetSizeStats('testcases/simple/output'),
|
||||
elmMarkup: assetSizeStats('testcases/elm-markup/output'),
|
||||
elmObjFile: assetSizeStats('testcases/elm-obj-file/output'),
|
||||
};
|
||||
|
||||
let results = [];
|
||||
results.push(await visitBenchmark(null, 'testcases/bench/standard.html'));
|
||||
results.push(
|
||||
await visitBenchmark('transformed', 'testcases/bench/transformed.html')
|
||||
);
|
||||
results.push(
|
||||
await visitBenchmark(null, 'testcases/elm-markup/standard.html')
|
||||
);
|
||||
results.push(
|
||||
await visitBenchmark('transformed', 'testcases/elm-markup/transformed.html')
|
||||
);
|
||||
results.push(
|
||||
await visitBenchmark(null, 'testcases/elm-obj-file/standard.html')
|
||||
);
|
||||
results.push(
|
||||
await visitBenchmark(
|
||||
'transformed',
|
||||
'testcases/elm-obj-file/transformed.html'
|
||||
)
|
||||
);
|
||||
|
||||
console.log(markdownNewResults(assets, reformat(results)));
|
||||
};
|
||||
|
||||
const markdownResults = (results: any): string => {
|
||||
let buffer: string[] = [];
|
||||
results.forEach((item: any) => {
|
||||
buffer.push('## ' + item.tag);
|
||||
buffer.push('*' + item.browser + '*');
|
||||
buffer.push('');
|
||||
item.results.forEach((result: any) => {
|
||||
buffer.push(' **' + result.name + '**');
|
||||
|
||||
if (result.status.status == 'success') {
|
||||
buffer.push(
|
||||
' ' +
|
||||
humanizeNumber(result.status.runsPerSecond).padStart(10, ' ') +
|
||||
' runs/sec (' +
|
||||
Math.round(result.status.goodnessOfFit * 100) +
|
||||
'%*)'
|
||||
);
|
||||
} else {
|
||||
buffer.push(' problem running benchmark');
|
||||
}
|
||||
|
||||
console.log(result);
|
||||
});
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
});
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
return buffer.join('\n');
|
||||
};
|
||||
|
||||
const markdownNewResults = (
|
||||
assets: { [key: string]: Stat[] },
|
||||
results: any
|
||||
): string => {
|
||||
let buffer: string[] = [];
|
||||
|
||||
buffer.push('# Benchmark results');
|
||||
buffer.push('');
|
||||
|
||||
// List asset sizes
|
||||
for (let key in assets) {
|
||||
buffer.push('## ' + key + ' asset overview');
|
||||
buffer.push('');
|
||||
assets[key].forEach((item: Stat) => {
|
||||
buffer.push(
|
||||
' ' +
|
||||
item.name.padEnd(40, ' ') +
|
||||
'' +
|
||||
humanizeNumber(
|
||||
roundToDecimal(1, item.bytes / Math.pow(2, 10))
|
||||
).padStart(10, ' ') +
|
||||
'kb'
|
||||
);
|
||||
});
|
||||
buffer.push('');
|
||||
}
|
||||
buffer.push('');
|
||||
|
||||
// List benchmarks
|
||||
for (let key in results) {
|
||||
buffer.push('## ' + key);
|
||||
buffer.push('');
|
||||
let base: number | null = null;
|
||||
results[key].forEach((item: any) => {
|
||||
let tag = '';
|
||||
if (item.tag != null) {
|
||||
tag = ', ' + item.tag;
|
||||
}
|
||||
if (base == null) {
|
||||
base = item.status.runsPerSecond;
|
||||
} else {
|
||||
let percentChange = (item.status.runsPerSecond / base) * 100;
|
||||
tag = tag + ' (' + Math.round(percentChange) + '%)';
|
||||
}
|
||||
|
||||
buffer.push(
|
||||
' ' +
|
||||
humanizeNumber(item.status.runsPerSecond).padStart(10, ' ') +
|
||||
' runs/sec (' +
|
||||
Math.round(item.status.goodnessOfFit * 100) +
|
||||
'%*), ' +
|
||||
item.browser +
|
||||
tag
|
||||
);
|
||||
});
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
}
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
return buffer.join('\n');
|
||||
};
|
||||
|
||||
/*
|
||||
Current shape
|
||||
{ browser: 'chrome
|
||||
, tag: 'transformed'
|
||||
, results: [
|
||||
name: 'sum 1000 entities in a list',
|
||||
status: {
|
||||
goodnessOfFit: 0.9924404521135742,
|
||||
runsPerSecond: 72127,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
{
|
||||
name: '1000 record updates',
|
||||
status: {
|
||||
goodnessOfFit: 0.9955251757469299,
|
||||
runsPerSecond: 2433,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
NewShape
|
||||
{ test: 'sum 1000 entities in a list'
|
||||
, results:
|
||||
[ { browser: 'chrome'
|
||||
, tag: 'transformed'
|
||||
, status: {
|
||||
goodnessOfFit: 0.9955251757469299,
|
||||
runsPerSecond: 2433,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
*/
|
||||
function reformat(results: any): any {
|
||||
let reformed: any = {};
|
||||
results.forEach((item: any) => {
|
||||
item.results.forEach((result: any) => {
|
||||
const newItem = {
|
||||
browser: item.browser,
|
||||
tag: item.tag,
|
||||
status: result.status,
|
||||
};
|
||||
if (result.name in reformed) {
|
||||
reformed[result.name].push(newItem);
|
||||
} else {
|
||||
reformed[result.name] = [newItem];
|
||||
}
|
||||
});
|
||||
});
|
||||
return reformed;
|
||||
}
|
||||
|
||||
// adds commas to the number so its easier to read.
|
||||
function humanizeNumber(x: number): string {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
function roundToDecimal(level: number, num: number): number {
|
||||
let factor: number = Math.pow(10, level);
|
||||
return Math.round(num * factor) / factor;
|
||||
}
|
||||
|
||||
run();
|
||||
go();
|
||||
|
194
src/reporting.ts
Normal file
194
src/reporting.ts
Normal file
@ -0,0 +1,194 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as Compile from './compile-testcases';
|
||||
import { Transforms, ObjectUpdate } from './types';
|
||||
import * as Visit from './visit';
|
||||
|
||||
export interface Stat {
|
||||
name: string;
|
||||
bytes: number;
|
||||
}
|
||||
|
||||
export const assetSizeStats = (dir: string): Stat[] => {
|
||||
let stats: Stat[] = [];
|
||||
fs.readdir(dir, function(err, files) {
|
||||
if (err) {
|
||||
console.log('Error getting directory information.');
|
||||
} else {
|
||||
files.forEach(function(file) {
|
||||
const stat = fs.statSync(path.join(dir, file));
|
||||
stats.push({
|
||||
name: path.basename(file),
|
||||
bytes: stat.size,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return stats;
|
||||
};
|
||||
|
||||
type Results = {
|
||||
assets: { [key: string]: Stat[] };
|
||||
benchmarks: any;
|
||||
};
|
||||
|
||||
export const markdown = (report: Results): string => {
|
||||
let buffer: string[] = [];
|
||||
|
||||
buffer.push('# Benchmark results');
|
||||
buffer.push('');
|
||||
|
||||
// List asset sizes
|
||||
for (let key in report.assets) {
|
||||
buffer.push('## ' + key + ' asset overview');
|
||||
buffer.push('');
|
||||
report.assets[key].forEach((item: Stat) => {
|
||||
buffer.push(
|
||||
' ' +
|
||||
item.name.padEnd(40, ' ') +
|
||||
'' +
|
||||
humanizeNumber(
|
||||
roundToDecimal(1, item.bytes / Math.pow(2, 10))
|
||||
).padStart(10, ' ') +
|
||||
'kb'
|
||||
);
|
||||
});
|
||||
buffer.push('');
|
||||
}
|
||||
buffer.push('');
|
||||
|
||||
// List benchmarks
|
||||
for (let key in report.benchmarks) {
|
||||
buffer.push('## ' + key);
|
||||
buffer.push('');
|
||||
let base: number | null = null;
|
||||
report.benchmarks[key].forEach((item: any) => {
|
||||
let tag = '';
|
||||
let delta: string = '';
|
||||
if (item.tag != null) {
|
||||
tag = ', ' + item.tag;
|
||||
}
|
||||
if (base == null) {
|
||||
base = item.status.runsPerSecond;
|
||||
} else {
|
||||
let percentChange = (item.status.runsPerSecond / base) * 100;
|
||||
delta = ' (' + Math.round(percentChange) + '%)';
|
||||
}
|
||||
|
||||
const goodness =
|
||||
'(' + Math.round(item.status.goodnessOfFit * 100) + '%*)';
|
||||
|
||||
const label = ' ' + item.browser + tag + goodness;
|
||||
const datapoint =
|
||||
humanizeNumber(item.status.runsPerSecond).padStart(10, ' ') +
|
||||
' runs/sec ' +
|
||||
delta;
|
||||
buffer.push(label.padEnd(40, ' ') + datapoint);
|
||||
});
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
}
|
||||
buffer.push('');
|
||||
buffer.push('');
|
||||
return buffer.join('\n');
|
||||
};
|
||||
|
||||
/*
|
||||
Current shape
|
||||
{ browser: 'chrome
|
||||
, tag: 'transformed'
|
||||
, results: [
|
||||
name: 'sum 1000 entities in a list',
|
||||
status: {
|
||||
goodnessOfFit: 0.9924404521135742,
|
||||
runsPerSecond: 72127,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
{
|
||||
name: '1000 record updates',
|
||||
status: {
|
||||
goodnessOfFit: 0.9955251757469299,
|
||||
runsPerSecond: 2433,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
NewShape
|
||||
{ test: 'sum 1000 entities in a list'
|
||||
, results:
|
||||
[ { browser: 'chrome'
|
||||
, tag: 'transformed'
|
||||
, status: {
|
||||
goodnessOfFit: 0.9955251757469299,
|
||||
runsPerSecond: 2433,
|
||||
status: 'success'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
*/
|
||||
export function reformat(results: any): any {
|
||||
let reformed: any = {};
|
||||
results.forEach((item: any) => {
|
||||
item.results.forEach((result: any) => {
|
||||
const newItem = {
|
||||
browser: item.browser,
|
||||
tag: item.tag,
|
||||
status: result.status,
|
||||
};
|
||||
if (result.name in reformed) {
|
||||
reformed[result.name].push(newItem);
|
||||
} else {
|
||||
reformed[result.name] = [newItem];
|
||||
}
|
||||
});
|
||||
});
|
||||
return reformed;
|
||||
}
|
||||
|
||||
// adds commas to the number so its easier to read.
|
||||
function humanizeNumber(x: number): string {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
function roundToDecimal(level: number, num: number): number {
|
||||
let factor: number = Math.pow(10, level);
|
||||
return Math.round(num * factor) / factor;
|
||||
}
|
||||
|
||||
type Testcase = {
|
||||
name: string;
|
||||
dir: string;
|
||||
elmFile: string;
|
||||
options: Transforms;
|
||||
};
|
||||
|
||||
export const run = async function(runnable: Testcase[]) {
|
||||
let results: any[] = [];
|
||||
let assets: any = {};
|
||||
|
||||
for (let instance of runnable) {
|
||||
await Compile.compileAndTransform(
|
||||
instance.dir,
|
||||
instance.elmFile,
|
||||
instance.options
|
||||
);
|
||||
assets[instance.name] = assetSizeStats(path.join(instance.dir, 'output'));
|
||||
|
||||
results.push(
|
||||
await Visit.benchmark(null, path.join(instance.dir, 'standard.html'))
|
||||
);
|
||||
results.push(
|
||||
await Visit.benchmark(
|
||||
'transformed',
|
||||
path.join(instance.dir, 'transformed.html')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return { assets: assets, benchmarks: reformat(results) };
|
||||
};
|
15
src/types.ts
15
src/types.ts
@ -11,3 +11,18 @@ export interface ElmVariant {
|
||||
slots: string[];
|
||||
totalTypeSlotCount: number;
|
||||
}
|
||||
|
||||
export type Transforms = {
|
||||
prepack: boolean;
|
||||
variantShapes: boolean;
|
||||
inlineFunctions: boolean;
|
||||
listLiterals: boolean;
|
||||
arrowFns: boolean;
|
||||
objectUpdate: ObjectUpdate | null;
|
||||
unusedValues: boolean;
|
||||
};
|
||||
|
||||
export enum ObjectUpdate {
|
||||
UseSpreadForUpdateAndOriginalRecord = 'for_both',
|
||||
UseSpreadOnlyToMakeACopy = 'for_copy',
|
||||
}
|
||||
|
23
src/visit.ts
Normal file
23
src/visit.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import * as Webdriver from 'selenium-webdriver';
|
||||
import * as chrome from 'selenium-webdriver/chrome';
|
||||
import * as Path from 'path';
|
||||
|
||||
export const benchmark = async (tag: string | null, file: string) => {
|
||||
let driver = new Webdriver.Builder()
|
||||
.forBrowser('chrome')
|
||||
// .setChromeOptions(/* ... */)
|
||||
// .setFirefoxOptions(/* ... */)
|
||||
.build();
|
||||
|
||||
// docs for selenium:
|
||||
// https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
|
||||
let result = [];
|
||||
try {
|
||||
await driver.get('file://' + Path.resolve(file));
|
||||
await driver.wait(Webdriver.until.titleIs('done'), 480000);
|
||||
result = await driver.executeScript('return window.results;');
|
||||
} finally {
|
||||
await driver.quit();
|
||||
}
|
||||
return { tag: tag, browser: 'chrome', results: result };
|
||||
};
|
Loading…
Reference in New Issue
Block a user