Use comlink in workers (#5915)

pull/5922/head
Paulus Schoutsen 2020-05-18 07:51:46 -07:00 committed by GitHub
parent d38a0f0366
commit a66d2ca1b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 81 deletions

View File

@ -2,6 +2,7 @@ const webpack = require("webpack");
const path = require("path"); const path = require("path");
const TerserPlugin = require("terser-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin");
const ManifestPlugin = require("webpack-manifest-plugin"); const ManifestPlugin = require("webpack-manifest-plugin");
const WorkerPlugin = require("worker-plugin");
const paths = require("./paths.js"); const paths = require("./paths.js");
const env = require("./env.js"); const env = require("./env.js");
const { babelLoaderConfig } = require("./babel.js"); const { babelLoaderConfig } = require("./babel.js");
@ -51,6 +52,7 @@ const createWebpackConfig = ({
], ],
}, },
plugins: [ plugins: [
new WorkerPlugin(),
new ManifestPlugin(), new ManifestPlugin(),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
__DEV__: !isProdBuild, __DEV__: !isProdBuild,
@ -105,7 +107,7 @@ const createWebpackConfig = ({
latestBuild ? "frontend_latest" : "frontend_es5" latestBuild ? "frontend_latest" : "frontend_es5"
), ),
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/", publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
// For workerize loader // To silence warning in worker plugin
globalObject: "self", globalObject: "self",
}, },
}; };

View File

@ -86,6 +86,7 @@
"chart.js": "~2.8.0", "chart.js": "~2.8.0",
"chartjs-chart-timeline": "^0.3.0", "chartjs-chart-timeline": "^0.3.0",
"codemirror": "^5.49.0", "codemirror": "^5.49.0",
"comlink": "^4.3.0",
"cpx": "^1.5.0", "cpx": "^1.5.0",
"deep-clone-simple": "^1.1.1", "deep-clone-simple": "^1.1.1",
"deep-freeze": "^0.0.1", "deep-freeze": "^0.0.1",
@ -108,6 +109,7 @@
"memoize-one": "^5.0.2", "memoize-one": "^5.0.2",
"moment": "^2.24.0", "moment": "^2.24.0",
"node-vibrant": "^3.1.5", "node-vibrant": "^3.1.5",
"proxy-polyfill": "^0.3.1",
"regenerator-runtime": "^0.13.2", "regenerator-runtime": "^0.13.2",
"resize-observer": "^1.0.0", "resize-observer": "^1.0.0",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
@ -195,7 +197,7 @@
"webpack-dev-server": "^3.10.3", "webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.0.4", "webpack-manifest-plugin": "^2.0.4",
"workbox-build": "^5.1.3", "workbox-build": "^5.1.3",
"workerize-loader": "^1.1.0" "worker-plugin": "^4.0.3"
}, },
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page", "_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
"_comment_2": "Fix in https://github.com/Polymer/polymer/pull/5569", "_comment_2": "Fix in https://github.com/Polymer/polymer/pull/5569",

View File

@ -14,9 +14,6 @@ import { classMap } from "lit-html/directives/class-map";
import { ifDefined } from "lit-html/directives/if-defined"; import { ifDefined } from "lit-html/directives/if-defined";
import { styleMap } from "lit-html/directives/style-map"; import { styleMap } from "lit-html/directives/style-map";
import { scroll } from "lit-virtualizer"; import { scroll } from "lit-virtualizer";
// @ts-ignore
// eslint-disable-next-line import/no-webpack-loader-syntax
import sortFilterWorker from "workerize-loader!./sort_filter_worker";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import "../../common/search/search-input"; import "../../common/search/search-input";
import { debounce } from "../../common/util/debounce"; import { debounce } from "../../common/util/debounce";
@ -24,6 +21,7 @@ import { nextRender } from "../../common/util/render-status";
import "../ha-checkbox"; import "../ha-checkbox";
import type { HaCheckbox } from "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox";
import "../ha-icon"; import "../ha-icon";
import { filterSortData } from "./sort-filter";
declare global { declare global {
// for fire event // for fire event
@ -117,8 +115,6 @@ export class HaDataTable extends LitElement {
private curRequest = 0; private curRequest = 0;
private _worker: any | undefined;
private _debounceSearch = debounce( private _debounceSearch = debounce(
(value: string) => { (value: string) => {
this._filter = value; this._filter = value;
@ -140,11 +136,6 @@ export class HaDataTable extends LitElement {
} }
} }
protected firstUpdated(properties: PropertyValues) {
super.firstUpdated(properties);
this._worker = sortFilterWorker();
}
protected updated(properties: PropertyValues) { protected updated(properties: PropertyValues) {
super.updated(properties); super.updated(properties);
@ -383,7 +374,7 @@ export class HaDataTable extends LitElement {
this.curRequest++; this.curRequest++;
const curRequest = this.curRequest; const curRequest = this.curRequest;
const filterProm = this._worker.filterSortData( const filterProm = filterSortData(
this.data, this.data,
this._sortColumns, this._sortColumns,
this._filter, this._filter,

View File

@ -0,0 +1,26 @@
import { wrap } from "comlink";
type FilterSortDataType = typeof import("./sort_filter_worker").api["filterSortData"];
type filterSortDataParamTypes = Parameters<FilterSortDataType>;
let worker: any | undefined;
export const filterSortData = async (
data: filterSortDataParamTypes[0],
columns: filterSortDataParamTypes[1],
filter: filterSortDataParamTypes[2],
direction: filterSortDataParamTypes[3],
sortColumn: filterSortDataParamTypes[4]
): Promise<ReturnType<FilterSortDataType>> => {
if (!worker) {
worker = wrap(new Worker("./sort_filter_worker", { type: "module" }));
}
return await worker.filterSortData(
data,
columns,
filter,
direction,
sortColumn
);
};

View File

@ -1,57 +1,34 @@
import memoizeOne from "memoize-one"; // To use comlink under ES5
// eslint-disable-next-line import/no-cycle import "proxy-polyfill";
import { import { expose } from "comlink";
DataTableColumnContainer, import type {
DataTableColumnData, DataTableSortColumnData,
DataTableRowData, DataTableRowData,
SortingDirection, SortingDirection,
HaDataTable,
} from "./ha-data-table"; } from "./ha-data-table";
export const filterSortData = memoizeOne( type SortableColumnContainer = HaDataTable["_sortColumns"];
async (
data: DataTableRowData[],
columns: DataTableColumnContainer,
filter: string,
direction: SortingDirection,
sortColumn?: string
) =>
sortColumn
? _memSortData(
await _memFilterData(data, columns, filter),
columns,
direction,
sortColumn
)
: _memFilterData(data, columns, filter)
);
const _memFilterData = memoizeOne( const filterSortData = (
async (
data: DataTableRowData[],
columns: DataTableColumnContainer,
filter: string
) => {
if (!filter) {
return data;
}
return filterData(data, columns, filter.toUpperCase());
}
);
const _memSortData = memoizeOne(
(
data: DataTableRowData[],
columns: DataTableColumnContainer,
direction: SortingDirection,
sortColumn: string
) => {
return sortData(data, columns[sortColumn], direction, sortColumn);
}
);
export const filterData = (
data: DataTableRowData[], data: DataTableRowData[],
columns: DataTableColumnContainer, columns: SortableColumnContainer,
filter: string,
direction: SortingDirection,
sortColumn?: string
) => {
const filteredData = filter ? filterData(data, columns, filter) : data;
if (!sortColumn) {
return filteredData;
}
return sortData(filteredData, columns, direction, sortColumn);
};
const filterData = (
data: DataTableRowData[],
columns: SortableColumnContainer,
filter: string filter: string
) => ) =>
data.filter((row) => { data.filter((row) => {
@ -70,9 +47,9 @@ export const filterData = (
}); });
}); });
export const sortData = ( const sortData = (
data: DataTableRowData[], data: DataTableRowData[],
column: DataTableColumnData, column: DataTableSortColumnData,
direction: SortingDirection, direction: SortingDirection,
sortColumn: string sortColumn: string
) => ) =>
@ -105,3 +82,10 @@ export const sortData = (
} }
return 0; return 0;
}); });
// Export for types
export const api = {
filterSortData,
};
expose(api);

View File

@ -1,10 +1,6 @@
import { customElement, property, UpdatingElement } from "lit-element"; import { customElement, property, UpdatingElement } from "lit-element";
// @ts-ignore
// eslint-disable-next-line import/no-webpack-loader-syntax
import markdownWorker from "workerize-loader!../resources/markdown_worker";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
import { renderMarkdown } from "../resources/render-markdown";
let worker: any | undefined;
@customElement("ha-markdown") @customElement("ha-markdown")
class HaMarkdown extends UpdatingElement { class HaMarkdown extends UpdatingElement {
@ -16,16 +12,11 @@ class HaMarkdown extends UpdatingElement {
protected update(changedProps) { protected update(changedProps) {
super.update(changedProps); super.update(changedProps);
if (!worker) {
worker = markdownWorker();
}
this._render(); this._render();
} }
private async _render() { private async _render() {
this.innerHTML = await worker.renderMarkdown( this.innerHTML = await renderMarkdown(
this.content, this.content,
{ {
breaks: this.breaks, breaks: this.breaks,

View File

@ -2,6 +2,8 @@ import objAssign from "es6-object-assign";
import "mdn-polyfills/Array.prototype.includes"; import "mdn-polyfills/Array.prototype.includes";
import "regenerator-runtime/runtime"; import "regenerator-runtime/runtime";
import "unfetch/polyfill"; import "unfetch/polyfill";
// To use comlink under ES5
import "proxy-polyfill";
objAssign.polyfill(); objAssign.polyfill();

View File

@ -1,3 +1,6 @@
// To use comlink under ES5
import "proxy-polyfill";
import { expose } from "comlink";
import marked from "marked"; import marked from "marked";
// @ts-ignore // @ts-ignore
import filterXSS from "xss"; import filterXSS from "xss";
@ -9,14 +12,14 @@ interface WhiteList {
let whiteListNormal: WhiteList | undefined; let whiteListNormal: WhiteList | undefined;
let whiteListSvg: WhiteList | undefined; let whiteListSvg: WhiteList | undefined;
export const renderMarkdown = ( const renderMarkdown = (
content: string, content: string,
markedOptions: object, markedOptions: object,
hassOptions: { hassOptions: {
// Do not allow SVG on untrusted content, it allows XSS. // Do not allow SVG on untrusted content, it allows XSS.
allowSvg?: boolean; allowSvg?: boolean;
} = {} } = {}
) => { ): string => {
if (!whiteListNormal) { if (!whiteListNormal) {
whiteListNormal = { whiteListNormal = {
...filterXSS.whiteList, ...filterXSS.whiteList,
@ -45,3 +48,10 @@ export const renderMarkdown = (
whiteList, whiteList,
}); });
}; };
// Export for types
export const api = {
renderMarkdown,
};
expose(api);

View File

@ -0,0 +1,18 @@
import { wrap } from "comlink";
type RenderMarkdownType = typeof import("./markdown_worker").api["renderMarkdown"];
type renderMarkdownParamTypes = Parameters<RenderMarkdownType>;
let worker: any | undefined;
export const renderMarkdown = async (
content: renderMarkdownParamTypes[0],
markedOptions: renderMarkdownParamTypes[1],
hassOptions?: renderMarkdownParamTypes[2]
): Promise<ReturnType<RenderMarkdownType>> => {
if (!worker) {
worker = wrap(new Worker("./markdown_worker", { type: "module" }));
}
return await worker.renderMarkdown(content, markedOptions, hassOptions);
};

View File

@ -5691,6 +5691,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
comlink@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.3.0.tgz#80b3366baccd87897dab3638ebfcfae28b2f87c7"
integrity sha512-mu4KKKNuW8TvkfpW/H88HBPeILubBS6T94BdD1VWBXNXfiyqVtwUCVNO1GeNOBTsIswzsMjWlycYr+77F5b84g==
command-line-args@^5.0.2: command-line-args@^5.0.2:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.0.tgz#632d3d3df35c8f0cc4365e442a3fd6d63b65621b" resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.0.tgz#632d3d3df35c8f0cc4365e442a3fd6d63b65621b"
@ -12146,6 +12151,11 @@ proxy-addr@~2.0.5:
forwarded "~0.1.2" forwarded "~0.1.2"
ipaddr.js "1.9.0" ipaddr.js "1.9.0"
proxy-polyfill@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.3.1.tgz#163d5283cf928dd8ddb5c5e88528e4ccd233496f"
integrity sha512-jywE1NIksgIGqZc4uF0QLbXGz2RcHQobsCkAW+8F0nr/6agap+TWksEAKyLnIBafPD88HT9qZR2ec0oomHdjcQ==
prr@~1.0.1: prr@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -15517,12 +15527,12 @@ worker-farm@^1.7.0:
dependencies: dependencies:
errno "~0.1.7" errno "~0.1.7"
workerize-loader@^1.1.0: worker-plugin@^4.0.3:
version "1.1.0" version "4.0.3"
resolved "https://registry.yarnpkg.com/workerize-loader/-/workerize-loader-1.1.0.tgz#d3a634390dcb685cc1ee292cd1fffeef0a646044" resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-4.0.3.tgz#7c42e600d5931ad154d3d5f187a32446df64db0f"
integrity sha512-cU2jPVE3AzzVxOonBe9lCCO//qwE9s/K4a9njFVRLueznzNDNND5vGHVorGuzK6xvamdDOZ9+g7CPIc7QKzucQ== integrity sha512-7hFDYWiKcE3yHZvemsoM9lZis/PzurHAEX1ej8PLCu818Rt6QqUAiDdxHPCKZctzmhqzPpcFSgvMCiPbtooqAg==
dependencies: dependencies:
loader-utils "^1.2.3" loader-utils "^1.1.0"
wrap-ansi@^2.0.0: wrap-ansi@^2.0.0:
version "2.1.0" version "2.1.0"