(core) Speed up and upgrade build.

Summary:
- Upgrades to build-related packages:
  - Upgrade typescript, related libraries and typings.
  - Upgrade webpack, eslint; add tsc-watch, node-dev, eslint_d.

- Build organization changes:
  - Build webpack from original typescript, transpiling only; with errors still
    reported by a background tsc watching process.

- Typescript-related changes:
  - Reduce imports of AWS dependencies (very noticeable speedup)
  - Avoid auto-loading global @types
  - Client code is now built with isolatedModules flag (for safe transpilation)
  - Use allowJs to avoid copying JS files manually.

- Linting changes
  - Enhance Arcanist ESLintLinter to run before/after commands, and set up to use eslint_d
  - Update eslint config, and include .eslintignore to avoid linting generated files.
  - Include a bunch of eslint-prompted and eslint-generated fixes
  - Add no-unused-expression rule to eslint, and fix a few warnings about it

- Other items:
  - Refactor cssInput to avoid circular dependency
  - Remove a bit of unused code, libraries, dependencies

Test Plan: No behavior changes, all existing tests pass. There are 30 tests fewer reported because `test_gpath.py` was removed (it's been unused for years)

Reviewers: paulfitz

Reviewed By: paulfitz

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D3498
This commit is contained in:
Dmitry S
2022-06-27 16:09:41 -04:00
parent 64ff9ccd0a
commit dd2eadc86e
45 changed files with 948 additions and 2442 deletions

View File

@@ -29,7 +29,7 @@ export class ChoiceTextBox extends NTextBox {
private _choiceValues: Computed<string[]>;
private _choiceValuesSet: Computed<Set<string>>;
private _choiceOptions: KoSaveableObservable<ChoiceOptions | null | undefined>;
private _choiceOptionsByName: Computed<ChoiceOptionsByName>
private _choiceOptionsByName: Computed<ChoiceOptionsByName>;
constructor(field: ViewFieldRec) {
super(field);

View File

@@ -17,6 +17,9 @@ export interface IMargins {
right: number;
}
export type IRect = ISize & IMargins;
// edgeMargin is how many pixels to leave before the edge of the browser window by default.
// This is added to margins that may be passed into the constructor.
const edgeMargin = 12;
@@ -37,8 +40,8 @@ export class EditorPlacement extends Disposable {
public readonly onReposition = this.autoDispose(new Emitter());
private _editorRoot: HTMLElement;
private _maxRect: ClientRect|DOMRect;
private _cellRect: ClientRect|DOMRect;
private _maxRect: IRect;
private _cellRect: IRect;
private _margins: IMargins;
// - editorDom is the DOM to attach. It gets destroyed when EditorPlacement is disposed.
@@ -141,7 +144,7 @@ export class EditorPlacement extends Disposable {
// Get the bounding rect of elem excluding borders. This allows the editor to match cellElem more
// closely which is more visible in case of DetailView.
function rectWithoutBorders(elem: Element): ClientRect {
function rectWithoutBorders(elem: Element): IRect {
const rect = elem.getBoundingClientRect();
const style = getComputedStyle(elem, null);
const bTop = parseFloat(style.getPropertyValue('border-top-width'));

View File

@@ -55,6 +55,7 @@ function getTypeDefinition(type: string | false) {
}
type ComputedStyle = {style?: Style; error?: true} | null | undefined;
/**
* Builds a font option computed property.
*/
@@ -62,12 +63,13 @@ function buildFontOptions(
builder: FieldBuilder,
computedRule: ko.Computed<ComputedStyle>,
optionName: keyof Style) {
return koUtil.withKoUtils(ko.computed(function() {
return koUtil.withKoUtils(ko.computed(() => {
if (builder.isDisposed()) { return false; }
const style = computedRule()?.style;
const styleFlag = style?.[optionName] || this.field[optionName]();
const styleFlag = style?.[optionName] || builder.field[optionName]();
return styleFlag;
}, builder)).onlyNotifyUnequal();
})).onlyNotifyUnequal();
}
/**
@@ -131,9 +133,9 @@ export class FieldBuilder extends Disposable {
});
// Observable which evaluates to a *function* that decides if a value is valid.
this._isRightType = ko.pureComputed(function() {
this._isRightType = ko.pureComputed<(value: CellValue, options?: any) => boolean>(() => {
return gristTypes.isRightType(this._readOnlyPureType()) || _.constant(false);
}, this);
});
// Returns a boolean indicating whether the column is type Reference or ReferenceList.
this._isRef = this.autoDispose(ko.computed(() => {
@@ -154,7 +156,7 @@ export class FieldBuilder extends Disposable {
}
}));
this.widget = ko.pureComputed({
this.widget = ko.pureComputed<object>({
owner: this,
read() { return this.options().widget; },
write(widget) {
@@ -196,10 +198,10 @@ export class FieldBuilder extends Disposable {
this._rowMap = new Map();
// Returns the constructor for the widget, and only notifies subscribers on changes.
this._widgetCons = this.autoDispose(koUtil.withKoUtils(ko.computed(function() {
this._widgetCons = this.autoDispose(koUtil.withKoUtils(ko.computed(() => {
return UserTypeImpl.getWidgetConstructor(this.options().widget,
this._readOnlyPureType());
}, this)).onlyNotifyUnequal());
})).onlyNotifyUnequal());
// Computed builder for the widget.
this.widgetImpl = this.autoDispose(koUtil.computedBuilder(() => {
@@ -467,28 +469,28 @@ export class FieldBuilder extends Disposable {
return { style : new CombinedStyle(styles, flags) };
}, this).extend({ deferred: true })).previousOnUndefined();
const widgetObs = koUtil.withKoUtils(ko.computed(function() {
const widgetObs = koUtil.withKoUtils(ko.computed(() => {
// TODO: Accessing row values like this doesn't always work (row and field might not be updated
// simultaneously).
if (this.isDisposed()) { return null; } // Work around JS errors during field removal.
const value = row.cells[this.field.colId()];
const cell = value && value();
if (value && this._isRightType()(cell, this.options) || row._isAddRow.peek()) {
if ((value) && this._isRightType()(cell, this.options) || row._isAddRow.peek()) {
return this.widgetImpl();
} else if (gristTypes.isVersions(cell)) {
return this.diffImpl;
} else {
return null;
}
}, this).extend({ deferred: true })).onlyNotifyUnequal();
}).extend({ deferred: true })).onlyNotifyUnequal();
const textColor = koUtil.withKoUtils(ko.computed(function() {
const textColor = koUtil.withKoUtils(ko.computed(() => {
if (this.isDisposed()) { return null; }
const fromRules = computedRule()?.style?.textColor;
return fromRules || this.field.textColor() || '';
}, this)).onlyNotifyUnequal();
})).onlyNotifyUnequal();
const fillColor = koUtil.withKoUtils(ko.computed(function() {
const fillColor = koUtil.withKoUtils(ko.computed(() => {
if (this.isDisposed()) { return null; }
const fromRules = computedRule()?.style?.fillColor;
let fill = fromRules || this.field.fillColor();
@@ -496,7 +498,7 @@ export class FieldBuilder extends Disposable {
// If there is no color we are using fully transparent white color (for tests mainly).
fill = fill ? fill.toUpperCase() : fill;
return (fill === '#FFFFFF' ? '' : fill) || '#FFFFFF00';
}, this)).onlyNotifyUnequal();
})).onlyNotifyUnequal();
const fontBold = buildFontOptions(this, computedRule, 'fontBold');
const fontItalic = buildFontOptions(this, computedRule, 'fontItalic');

View File

@@ -135,6 +135,7 @@ export class NTextEditor extends NewBaseEditor {
// but we got same enough spaces, we will force browser to check the available space once more time.
if (enoughSpace(rect, size) && hasScroll(textInput)) {
textInput.style.overflow = "hidden";
// eslint-disable-next-line no-unused-expressions
textInput.clientHeight; // just access metrics is enough to repaint
textInput.style.overflow = "auto";
}

View File

@@ -14,6 +14,7 @@ import {
dom,
DomContents,
fromKo,
IDisposableOwnerT,
Observable,
} from 'grainjs';
@@ -30,8 +31,13 @@ export abstract class NewAbstractWidget extends Disposable {
/**
* Override the create() method to match the parameters of create() expected by FieldBuilder.
*/
public static create(field: ViewFieldRec) {
return Disposable.create.call(this as any, null, field);
// We copy Disposable.create() signature (the second one) to pacify typescript, but code must
// use the first signature, which is compatible with old-style constructors.
public static create<T extends new (...args: any[]) => any>(field: ViewFieldRec): InstanceType<T>;
public static create<T extends new (...args: any[]) => any>(
this: T, owner: IDisposableOwnerT<InstanceType<T>>|null, ...args: ConstructorParameters<T>): InstanceType<T>;
public static create(...args: any[]) {
return Disposable.create.call(this as any, null, ...args);
}
protected options: SaveableObjObservable<any>;