Skip to content

Commit

Permalink
studio-ui bundling (#368)
Browse files Browse the repository at this point in the history
Bundles studio-ui to reduce multiple round trips made by the browser to
the vite dev server.
The browser still makes network requests for things like localData and
component files.
One way to reduce perceived lag here is server side rendering studio.
Another is the loading indicator we have planned.

DOMContentLoaded is now 412ms instead of 5.09s. 
There should be a bigger improvement in CBD due to network requests
taking longer there compared to local.
5.0MB transferred instead of 14.6MB (could be smaller probably but still
yay!)

Removes ts-morph/typescript dependencies from TypeGuards and by
extension the ui bundle (they are big packages).
Updates lodash imports to use smaller scoped imports.
Adds vite plugins for bundle size, css in js, dts files, and svg
imports.

J=SLAP-2921
TEST=manual

I can start up studio and see less requests in the network tab

old network tab

https://github.com/yext/studio/assets/23005393/022d6199-5fa6-47db-b84b-5e543c729ae3

new network tab

![image](https://github.com/yext/studio/assets/23005393/45c9d4d1-b25c-4d16-bb0a-fdbe5ca01d3c)
  • Loading branch information
oshi97 authored and alextaing committed Sep 20, 2023
1 parent 9f9e6b2 commit 4b19926
Show file tree
Hide file tree
Showing 22 changed files with 1,388 additions and 774 deletions.
1 change: 1 addition & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ jobs:
- run: npm run build
- run: npm run build-test-site -w=apps/test-site
- run: npm run typecheck-jest
- run: npm run size-limit -w=packages/studio-ui
2,040 changes: 1,305 additions & 735 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions packages/studio-plugin/src/parsers/ComponentTreeParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { v4 } from "uuid";
import { FileMetadataKind, TypelessPropVal } from "../types";
import StudioSourceFileParser from "./StudioSourceFileParser";
import StaticParsingHelpers from "./helpers/StaticParsingHelpers";
import TypeGuards from "../utils/TypeGuards";
import ParsingOrchestrator from "../orchestrators/ParsingOrchestrator";
import MissingPropsChecker from "./MissingPropsChecker";

Expand Down Expand Up @@ -77,7 +76,7 @@ export default class ComponentTreeParser {
);
}

if (!TypeGuards.isNotFragmentElement(component)) {
if (!ComponentTreeParser.isNotFragmentElement(component)) {
return {
...commonComponentState,
kind: ComponentStateKind.Fragment,
Expand All @@ -98,6 +97,19 @@ export default class ComponentTreeParser {
};
}

private static isNotFragmentElement(
element: JsxElement | JsxSelfClosingElement | JsxFragment
): element is JsxElement | JsxSelfClosingElement {
if (element.isKind(SyntaxKind.JsxFragment)) {
return false;
}
if (element.isKind(SyntaxKind.JsxSelfClosingElement)) {
return true;
}
const name = StaticParsingHelpers.parseJsxElementName(element);
return !["Fragment", "React.Fragment"].includes(name);
}

private parseElement(
component: JsxElement | JsxSelfClosingElement,
componentName: string,
Expand Down
20 changes: 0 additions & 20 deletions packages/studio-plugin/src/utils/TypeGuards.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
import {
JsxElement,
JsxFragment,
JsxSelfClosingElement,
SyntaxKind,
} from "ts-morph";
import {
ComponentState,
ComponentStateKind,
Expand All @@ -18,7 +12,6 @@ import {
SiteSettingsValues,
} from "../types";

import StaticParsingHelpers from "../parsers/helpers/StaticParsingHelpers";
import {
SiteSettingsExpression,
StreamsDataExpression,
Expand Down Expand Up @@ -159,19 +152,6 @@ export default class TypeGuards {
return typeof value === "string" && value.startsWith("siteSettings.");
}

static isNotFragmentElement(
element: JsxElement | JsxSelfClosingElement | JsxFragment
): element is JsxElement | JsxSelfClosingElement {
if (element.isKind(SyntaxKind.JsxFragment)) {
return false;
}
if (element.isKind(SyntaxKind.JsxSelfClosingElement)) {
return true;
}
const name = StaticParsingHelpers.parseJsxElementName(element);
return !["Fragment", "React.Fragment"].includes(name);
}

static isSiteSettingsValues(
propValues: PropValues
): propValues is SiteSettingsValues {
Expand Down
1 change: 1 addition & 0 deletions packages/studio-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
stats.html
7 changes: 7 additions & 0 deletions packages/studio-ui/.size-limit.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = [
{
path: "lib/src/index.js",
limit: "700 kB",
gzip: false,
},
];
13 changes: 10 additions & 3 deletions packages/studio-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
"scripts": {
"dev": "npm run copy-svg && tsc --watch --preserveWatchOutput -p tsconfig.json",
"copy-svg": "npx copyfiles \"src/**/*.svg\" lib",
"build": "rimraf lib && npm run copy-svg && tsc -p tsconfig.json",
"build": "vite build",
"test": "jest",
"typecheck-jest": "npx tsc -p tests/tsconfig.json"
"typecheck-jest": "npx tsc -p tests/tsconfig.json",
"size-limit": "size-limit"
},
"dependencies": {
"@dhmk/zustand-lens": "^2.0.5",
Expand Down Expand Up @@ -49,6 +50,7 @@
"@babel/plugin-syntax-flow": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.19.0",
"@rollup/plugin-typescript": "^10.0.1",
"@size-limit/file": "^9.0.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
Expand All @@ -64,7 +66,12 @@
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.3.1",
"resize-observer-polyfill": "^1.5.1",
"vite-plugin-svgr": "^3.2.0"
"rollup-plugin-visualizer": "^5.9.2",
"size-limit": "^9.0.0",
"vite": "^4.4.7",
"vite-plugin-css-injected-by-js": "^3.3.0",
"vite-plugin-dts": "^3.5.3",
"vite-plugin-svgr": "^2.4.0"
},
"peerDependencies": {
"@yext/studio-plugin": "*"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, MouseEvent, CSSProperties } from "react";
import { ReactComponent as VectorIcon } from "../../icons/vector.svg";
import { startCase } from "lodash";
import startCase from "lodash/startCase";

const listStyles: CSSProperties = {
minWidth: "200px",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";
import { Component, PropsWithChildren, ReactInstance } from "react";
import DOMRectProperties from "../store/models/DOMRectProperties";
import useStudioStore from "../store/useStudioStore";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { StaticPageSettings } from "./StaticPageModal";
import { streamScopeFormData } from "../AddPageButton/StreamScopeCollector";
import PageDataValidator from "../../utils/PageDataValidator";
import { toast } from "react-toastify";
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";

type EntityPageSettings = StaticPageSettings & StreamScopeForm;

Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/components/SiteSettingsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
SiteSettingsVal,
} from "@yext/studio-plugin";
import React, { useCallback } from "react";
import { startCase } from "lodash";
import startCase from "lodash/startCase";
import useStudioStore from "../store/useStudioStore";
import PropInput from "./PropInput";

Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/components/common/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeEvent, useEffect, useMemo, useState } from "react";
import { debounce } from "lodash";
import debounce from "lodash/debounce";
import PropValueHelpers from "../../utils/PropValueHelpers";
import { PropValueKind, PropValueType } from "@yext/studio-plugin";

Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/hooks/useFuncWithZundoBatching.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react";
import useTemporalStore from "../store/useTemporalStore";
import { debounce } from "lodash";
import debounce from "lodash/debounce";

/**
* Updates a function so it doesn't trigger Zundo store updates until after a
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/hooks/useHasChanges.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import useStudioStore from "../store/useStudioStore";
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";

export default function useHasChanges() {
// TODO(SLAP-2556) Refactor pendingChanges to use PreviousSaveSlice
Expand Down
1 change: 1 addition & 0 deletions packages/studio-ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as App } from "./App";
export { default as hotReloadStore } from "./store/hotReloadStore";
export { StudioHMRUpdateID } from "@yext/studio-plugin";
2 changes: 1 addition & 1 deletion packages/studio-ui/src/store/StudioActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import FileMetadataSlice from "./models/slices/FileMetadataSlice";
import PageSlice from "./models/slices/PageSlice";
import sendMessage from "../messaging/sendMessage";
import { cloneDeep } from "lodash";
import cloneDeep from "lodash/cloneDeep";
import SiteSettingsSlice from "./models/slices/SiteSettingsSlice";
import PreviousSaveSlice from "./models/slices/PreviousSaveSlice";
import StudioConfigSlice from "./models/slices/StudioConfigSlice";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { Stream } from "@yext/pages";
import PageSlice from "../models/slices/PageSlice";
import sendMessage from "../../messaging/sendMessage";
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";
import StudioActions from "../StudioActions";

export default class GenerateTestDataAction {
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/store/slices/createPageSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
PageState,
StreamScope,
} from "@yext/studio-plugin";
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";
import initialStudioData from "virtual_yext-studio";
import DOMRectProperties from "../models/DOMRectProperties";
import PageSlice, { PageSliceStates } from "../models/slices/PageSlice";
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/store/zundoMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PageSlice from "./models/slices/PageSlice";
import SiteSettingSlice from "./models/slices/SiteSettingsSlice";
import { StudioStore } from "./models/StudioStore";
import { isEqual } from "lodash";
import isEqual from "lodash/isEqual";
import { ZundoOptions, temporal } from "zundo";
import { TemporalStudioStore } from "./useTemporalStore";
import { StateCreator } from "zustand";
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-ui/src/utils/getPropsForPreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
PropVal,
PropType,
} from "@yext/studio-plugin";
import { get } from "lodash";
import get from "lodash/get";
import TemplateExpressionFormatter from "./TemplateExpressionFormatter";

/**
Expand Down
35 changes: 35 additions & 0 deletions packages/studio-ui/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// vite.config.js
import { resolve } from "path";
import { defineConfig, PluginOption } from "vite";
import svgr from "vite-plugin-svgr";
import { visualizer } from "rollup-plugin-visualizer";
import dts from "vite-plugin-dts";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";

export default defineConfig({
plugins: [
svgr(),
dts(),
cssInjectedByJsPlugin(),
visualizer() as PluginOption,
],
build: {
outDir: "lib",
sourcemap: true,
lib: {
entry: resolve(__dirname, "src/index.ts"),
formats: ["es"],
fileName: "src/index",
},
rollupOptions: {
external: [
"virtual_yext-studio-git-data",
"virtual_yext-studio",
"@pathToUserProjectRoot/tailwind.config",
"react",
"react-dom",
"react/jsx-runtime",
],
},
},
});
4 changes: 2 additions & 2 deletions packages/studio/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App, hotReloadStore } from "@yext/studio-ui";
import { StudioHMRPayload, StudioHMRUpdateID } from "@yext/studio-plugin";
import { App, hotReloadStore, StudioHMRUpdateID } from "@yext/studio-ui";
import type { StudioHMRPayload } from "@yext/studio-plugin";
import "./tailwind-directives.css";

if (import.meta.hot) {
Expand Down

0 comments on commit 4b19926

Please sign in to comment.