Skip to content

Commit

Permalink
#7670: Simplify creation of isolated widgets (IsolatedComponent) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante authored Apr 10, 2024
1 parent f118a93 commit 5a4565c
Show file tree
Hide file tree
Showing 34 changed files with 677 additions and 301 deletions.
7 changes: 5 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
CHROME_MANIFEST_KEY=
CHROME_EXTENSION_ID=mpjjildhmpddojocokjkgmlkkkfjnepo

# Chrome extension manifest version. Default is MV=2
# MV=3
# Chrome extension manifest version. Default is MV=3
# MV=2

# Shadow DOM mode for all components. Default is SHADOW_DOM=closed in regular webpack builds, open elsewhere
# SHADOW_DOM=open

# This makes all optional permissions required in the manifest.json to avoid permission popups. Only required for Playwright tests.
# REQUIRE_OPTIONAL_PERMISSIONS_IN_MANIFEST=1
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ jobs:
timeout-minutes: 60
runs-on: ubuntu-latest
env:
SHADOW_DOM: open
SERVICE_URL: https://app.pixiebrix.com
MV: ${{ matrix.MV }}
CHROME_MANIFEST_KEY: ${{ matrix.CHROME_MANIFEST_KEY }}
Expand Down
35 changes: 24 additions & 11 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,25 @@ const config = {
silent: true,
testEnvironment: "./src/testUtils/FixJsdomEnvironment.js",
modulePaths: ["/src"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "yaml", "yml", "json"],
moduleFileExtensions: [
"ts",
"tsx",
"js",
"jsx",
"mjs",
"yaml",
"yml",
"json",
],
modulePathIgnorePatterns: ["<rootDir>/headers.json", "<rootDir>/dist/"],
testPathIgnorePatterns: ["/end-to-end-tests"],
transform: {
"^.+\\.[jt]sx?$": "@swc/jest",
"^.+\\.mjs$": "@swc/jest",
"^.+\\.ya?ml$": "yaml-jest-transform",
"^.+\\.ya?ml\\?loadAsText$":
"<rootDir>/src/testUtils/rawJestTransformer.mjs",
"^.+\\.txt$": "<rootDir>/src/testUtils/rawJestTransformer.mjs",
"\\.[jt]sx?$": "@swc/jest",
"\\.mjs$": "@swc/jest",
"\\.ya?ml$": "yaml-jest-transform",
"\\.txt$": "<rootDir>/src/testUtils/rawJestTransformer.mjs",
// Note: `?param` URLs aren't supported here: https://github.com/jestjs/jest/pull/6282
// You can only use a mock via `moduleNameMapper` for these.
},
transformIgnorePatterns: [`node_modules/(?!${esmPackages.join("|")})`],
setupFiles: [
Expand All @@ -89,11 +98,15 @@ const config = {
"!**/vendor/**",
],
moduleNameMapper: {
"^@contrib/([^?]+)": "<rootDir>/contrib/$1",
"^@schemas/([^?]+)": "<rootDir>/schemas/$1",

"\\.s?css$": "identity-obj-proxy",
"\\.(gif|svg|png)$|\\?loadAsUrl$|\\?loadAsComponent$":
"<rootDir>/src/__mocks__/stringMock.js",
"^@contrib/(.*?)(\\?loadAsText)?$": "<rootDir>/contrib/$1",
"^@schemas/(.*)": "<rootDir>/schemas/$1",
"\\.(gif|svg|png)$": "<rootDir>/src/__mocks__/stringMock.js",

"\\?loadAsUrl$": "<rootDir>/src/__mocks__/stringMock.js",
"\\?loadAsText$": "<rootDir>/src/__mocks__/stringMock.js",
"\\?loadAsComponent$": "<rootDir>/src/__mocks__/stringMock.js",

// Auto-mocks. See documentation in ./src/__mocks__/readme.md
"^@/(.*)$": ["<rootDir>/src/__mocks__/@/$1", "<rootDir>/src/$1"],
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@uipath/robot": "1.3.1",
"@vespaiach/axios-fetch-adapter": "^0.3.1",
"@xobotyi/scrollbar-width": "^1.9.5",
"abort-utils": "^1.1.0",
"abort-utils": "^1.2.0",
"ace-builds": "^1.32.9",
"autocompleter": "^9.1.2",
"axios": "^0.27.2",
Expand Down
14 changes: 12 additions & 2 deletions scripts/DiscardFilePlugin.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import webpack from "webpack";

// https://github.com/pixiebrix/pixiebrix-extension/pull/7363#discussion_r1458224740
export default class DiscardFilePlugin {
constructor(filesToDiscard) {
this.filesToDiscard = filesToDiscard;
}

apply(compiler) {
compiler.hooks.compilation.tap("DiscardFilePlugin", (compilation) => {
compilation.hooks.processAssets.tapPromise(
Expand All @@ -9,11 +14,16 @@ export default class DiscardFilePlugin {
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
},
async (assets) => {
for (const componentPath of this.filesToDiscard) {
delete assets[`${componentPath.split("/").pop()}.js`];
// If `delete assets[]` causes issues in the future, try replacing the content instead:
// assets["DocumentView.js"] = new webpack.sources.RawSource('"Dropped"');
}

// TODO: Use <IsolatedComponent/> and move these to isolatedComponentList
delete assets["DocumentView.js"];
delete assets["EphemeralFormContent.js"];
delete assets["CustomFormComponent.js"];
// If this causes issues in the future, try replacing the content instead:
// assets["DocumentView.js"] = new webpack.sources.RawSource('"Dropped"');
},
);
});
Expand Down
24 changes: 3 additions & 21 deletions scripts/__snapshots__/manifest.test.js.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 73 additions & 10 deletions src/__snapshots__/Storyshots.test.js.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 8 additions & 11 deletions src/bricks/renderers/PropertyTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import "primereact/resources/themes/saga-blue/theme.css";
import "primereact/resources/primereact.min.css";
import "primeicons/primeicons.css";

import { TreeTable } from "primereact/treetable";
import type TreeNode from "primereact/treenode";
import { Column } from "primereact/column";
import { Stylesheets } from "@/components/Stylesheets";
import React from "react";

import theme from "primereact/resources/themes/saga-blue/theme.css?loadAsUrl";
import primereact from "primereact/resources/primereact.min.css?loadAsUrl";
import primeicons from "primeicons/primeicons.css?loadAsUrl";

const PropertyTree: React.FunctionComponent<{ value: TreeNode[] }> = ({
value,
}) => (
<Stylesheets href={[theme, primereact, primeicons]}>
<TreeTable value={value}>
<Column field="name" header="Property" expander />
<Column field="value" header="Value" />
</TreeTable>
</Stylesheets>
<TreeTable value={value}>
<Column field="name" header="Property" expander />
<Column field="value" header="Value" />
</TreeTable>
);

export default PropertyTree;
18 changes: 14 additions & 4 deletions src/bricks/renderers/propertyTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { sortBy, isPlainObject } from "lodash";
import { type BrickArgs, type BrickOptions } from "@/types/runtimeTypes";
import { canParseUrl } from "@/utils/urlUtils";
import { propertiesToSchema } from "@/utils/schemaUtils";
import IsolatedComponent from "@/components/IsolatedComponent";
import type TreeNode from "primereact/treenode";

interface Item {
key: string;
Expand Down Expand Up @@ -115,13 +117,21 @@ export class PropertyTableRenderer extends RendererABC {
);

async render({ data }: BrickArgs, { ctxt }: BrickOptions) {
const PropertyTree = await import(
/* webpackChunkName: "widgets" */
"./PropertyTree"
const PropertyTree: React.FC<{ value: TreeNode[] }> = ({ value }) => (
<IsolatedComponent
name="PropertyTree"
lazy={async () =>
import(
/* webpackChunkName: "isolated/PropertyTree" */
"./PropertyTree"
)
}
factory={(PropertyTree) => <PropertyTree value={value} />}
/>
);

return {
Component: PropertyTree.default,
Component: PropertyTree,
props: {
value: shapeData(data ?? ctxt),
},
Expand Down
13 changes: 10 additions & 3 deletions src/components/EmotionShadowRoot.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-type-assertion --
"Every property exists" (via Proxy), TypeScript doesn't offer such type
Also strictNullChecks config mismatch */
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
Expand All @@ -19,10 +23,13 @@
import EmotionShadowRoot from "react-shadow/emotion";
import { type CSSProperties } from "react";

/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-type-assertion --
"Every property exists" (via Proxy), TypeScript doesn't offer such type
Also strictNullChecks config mismatch */
/**
* Wrap components in a shadow DOM. This isolates them from styles inherited from
* the host website. To support react-select and any future potential emotion
* components we used the emotion variant of the react-shadow library.
*/
const ShadowRoot = EmotionShadowRoot.div!;
// TODO: Use EmotionShadowRoot["pixiebrix-widget"] to avoid any CSS conflicts. Requires snapshot/test updates

export const styleReset: CSSProperties = {
all: "initial",
Expand Down
Loading

0 comments on commit 5a4565c

Please sign in to comment.