Skip to content

Commit e179f51

Browse files
committed
chore: Improve bundle size
1 parent 35d4766 commit e179f51

File tree

11 files changed

+75
-186
lines changed

11 files changed

+75
-186
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ cli/testdata/.gen-golden
3636
/dist/
3737
site/out/
3838

39+
# Bundle analysis
40+
site/stats/
41+
3942
*.tfstate
4043
*.tfstate.backup
4144
*.tfplan

site/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"test": "jest --selectProjects test",
2424
"test:coverage": "jest --selectProjects test --collectCoverage",
2525
"test:watch": "jest --selectProjects test --watch",
26-
"typegen": "xstate typegen 'src/**/*.ts'"
26+
"typegen": "xstate typegen 'src/**/*.ts'",
27+
"stats": "STATS=true yarn build && npx http-server ./stats -p 8081 -c-1"
2728
},
2829
"dependencies": {
2930
"@emoji-mart/data": "1.0.5",
@@ -56,6 +57,7 @@
5657
"i18next": "21.9.1",
5758
"js-untar": "2.0.0",
5859
"just-debounce-it": "3.1.1",
60+
"lodash": "4.17.21",
5961
"playwright": "^1.29.2",
6062
"react": "18.2.0",
6163
"react-chartjs-2": "4.3.1",
@@ -67,6 +69,7 @@
6769
"react-router-dom": "6.4.1",
6870
"react-syntax-highlighter": "15.5.0",
6971
"remark-gfm": "3.0.1",
72+
"rollup-plugin-visualizer": "5.9.0",
7073
"sourcemapped-stacktrace": "1.1.11",
7174
"tzdata": "1.0.30",
7275
"ua-parser-js": "1.0.2",

site/src/components/IconField/IconField.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import Button from "@material-ui/core/Button"
22
import InputAdornment from "@material-ui/core/InputAdornment"
33
import Popover from "@material-ui/core/Popover"
4-
import TextField, { TextFieldProps } from "@material-ui/core/TextField"
4+
import TextField from "@material-ui/core/TextField"
55
import { OpenDropdown } from "components/DropdownArrows/DropdownArrows"
66
import { useRef, FC, useState } from "react"
77
import Picker from "@emoji-mart/react"
88
import { makeStyles } from "@material-ui/core/styles"
99
import { colors } from "theme/colors"
1010
import { useTranslation } from "react-i18next"
1111
import data from "@emoji-mart/data/sets/14/twitter.json"
12+
import { IconFieldProps } from "./types"
1213

13-
export const IconField: FC<
14-
TextFieldProps & { onPickEmoji: (value: string) => void }
15-
> = ({ onPickEmoji, ...textFieldProps }) => {
14+
const IconField: FC<IconFieldProps> = ({ onPickEmoji, ...textFieldProps }) => {
1615
if (
1716
typeof textFieldProps.value !== "string" &&
1817
typeof textFieldProps.value !== "undefined"
@@ -111,3 +110,5 @@ const useStyles = makeStyles((theme) => ({
111110
paddingBottom: theme.spacing(0.5),
112111
},
113112
}))
113+
114+
export default IconField
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { lazy, FC, Suspense } from "react"
2+
import { IconFieldProps } from "./types"
3+
4+
const IconField = lazy(() => import("./IconField"))
5+
6+
export const LazyIconField: FC<IconFieldProps> = (props) => {
7+
return (
8+
<Suspense>
9+
<IconField {...props} />
10+
</Suspense>
11+
)
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { TextFieldProps } from "@material-ui/core/TextField"
2+
3+
export type IconFieldProps = TextFieldProps & {
4+
onPickEmoji: (value: string) => void
5+
}

site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
TemplateExample,
88
} from "api/typesGenerated"
99
import { FormFooter } from "components/FormFooter/FormFooter"
10-
import { IconField } from "components/IconField/IconField"
1110
import { ParameterInput } from "components/ParameterInput/ParameterInput"
1211
import { Stack } from "components/Stack/Stack"
1312
import {
@@ -23,6 +22,7 @@ import { CreateTemplateData } from "xServices/createTemplate/createTemplateXServ
2322
import * as Yup from "yup"
2423
import { WorkspaceBuildLogs } from "components/WorkspaceBuildLogs/WorkspaceBuildLogs"
2524
import { HelpTooltip, HelpTooltipText } from "components/Tooltips/HelpTooltip"
25+
import { LazyIconField } from "components/IconField/LazyIconField"
2626

2727
const validationSchema = Yup.object({
2828
name: nameValidator("Name"),
@@ -154,7 +154,7 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = ({
154154
variant="outlined"
155155
/>
156156

157-
<IconField
157+
<LazyIconField
158158
{...getFieldHelpers("icon")}
159159
disabled={isSubmitting}
160160
onChange={onChangeTrimmed(form)}
Lines changed: 6 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
import data from "@emoji-mart/data/sets/14/twitter.json"
2-
import Picker from "@emoji-mart/react"
3-
import Button from "@material-ui/core/Button"
4-
import InputAdornment from "@material-ui/core/InputAdornment"
5-
import Popover from "@material-ui/core/Popover"
6-
import { makeStyles } from "@material-ui/core/styles"
71
import TextField from "@material-ui/core/TextField"
82
import { Group } from "api/typesGenerated"
93
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
10-
import { OpenDropdown } from "components/DropdownArrows/DropdownArrows"
114
import { FormFooter } from "components/FormFooter/FormFooter"
125
import { FullPageForm } from "components/FullPageForm/FullPageForm"
6+
import { LazyIconField } from "components/IconField/LazyIconField"
137
import { FullScreenLoader } from "components/Loader/FullScreenLoader"
148
import { Margins } from "components/Margins/Margins"
159
import { useFormik } from "formik"
16-
import { useRef, useState, FC } from "react"
10+
import { FC } from "react"
1711
import { useTranslation } from "react-i18next"
18-
import { colors } from "theme/colors"
1912
import { getFormHelpers, nameValidator, onChangeTrimmed } from "util/formUtils"
2013
import * as Yup from "yup"
2114

@@ -37,7 +30,6 @@ const UpdateGroupForm: FC<{
3730
onCancel: () => void
3831
isLoading: boolean
3932
}> = ({ group, errors, onSubmit, onCancel, isLoading }) => {
40-
const [isEmojiPickerOpen, setIsEmojiPickerOpen] = useState(false)
4133
const form = useFormik<FormData>({
4234
initialValues: {
4335
name: group.name,
@@ -48,9 +40,6 @@ const UpdateGroupForm: FC<{
4840
onSubmit,
4941
})
5042
const getFieldHelpers = getFormHelpers<FormData>(form, errors)
51-
const hasIcon = form.values.avatar_url && form.values.avatar_url !== ""
52-
const emojiButtonRef = useRef<HTMLButtonElement>(null)
53-
const styles = useStyles()
5443
const { t } = useTranslation("common")
5544

5645
return (
@@ -65,65 +54,16 @@ const UpdateGroupForm: FC<{
6554
label="Name"
6655
variant="outlined"
6756
/>
68-
<TextField
57+
58+
<LazyIconField
6959
{...getFieldHelpers("avatar_url")}
7060
onChange={onChangeTrimmed(form)}
71-
autoFocus
7261
fullWidth
73-
label="Icon"
62+
label={t("form.fields.icon")}
7463
variant="outlined"
75-
InputProps={{
76-
endAdornment: hasIcon ? (
77-
<InputAdornment position="end">
78-
<img
79-
alt=""
80-
src={form.values.avatar_url}
81-
className={styles.adornment}
82-
// This prevent browser to display the ugly error icon if the
83-
// image path is wrong or user didn't finish typing the url
84-
onError={(e) => (e.currentTarget.style.display = "none")}
85-
onLoad={(e) => (e.currentTarget.style.display = "inline")}
86-
/>
87-
</InputAdornment>
88-
) : undefined,
89-
}}
64+
onPickEmoji={(value) => form.setFieldValue("avatar_url", value)}
9065
/>
9166

92-
<Button
93-
fullWidth
94-
ref={emojiButtonRef}
95-
variant="outlined"
96-
size="small"
97-
endIcon={<OpenDropdown />}
98-
onClick={() => {
99-
setIsEmojiPickerOpen((v) => !v)
100-
}}
101-
>
102-
{t("emojiPicker.select")}
103-
</Button>
104-
105-
<Popover
106-
id="emoji"
107-
open={isEmojiPickerOpen}
108-
anchorEl={emojiButtonRef.current}
109-
onClose={() => {
110-
setIsEmojiPickerOpen(false)
111-
}}
112-
>
113-
<Picker
114-
theme="dark"
115-
data={data}
116-
onEmojiSelect={(emojiData) => {
117-
form
118-
.setFieldValue("avatar_url", `/emojis/${emojiData.unified}.png`)
119-
.catch((ex) => {
120-
console.error(ex)
121-
})
122-
setIsEmojiPickerOpen(false)
123-
}}
124-
/>
125-
</Popover>
126-
12767
<TextField
12868
{...getFieldHelpers("quota_allowance")}
12969
onChange={onChangeTrimmed(form)}
@@ -182,21 +122,4 @@ export const SettingsGroupPageView: FC<SettingsGroupPageViewProps> = ({
182122
)
183123
}
184124

185-
const useStyles = makeStyles((theme) => ({
186-
"@global": {
187-
"em-emoji-picker": {
188-
"--rgb-background": theme.palette.background.paper,
189-
"--rgb-input": colors.gray[17],
190-
"--rgb-color": colors.gray[4],
191-
},
192-
},
193-
adornment: {
194-
width: theme.spacing(3),
195-
height: theme.spacing(3),
196-
},
197-
iconField: {
198-
paddingBottom: theme.spacing(0.5),
199-
},
200-
}))
201-
202125
export default SettingsGroupPageView

site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx

Lines changed: 11 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
import Box from "@material-ui/core/Box"
22
import Checkbox from "@material-ui/core/Checkbox"
33
import Typography from "@material-ui/core/Typography"
4-
import data from "@emoji-mart/data/sets/14/twitter.json"
5-
import Picker from "@emoji-mart/react"
6-
import Button from "@material-ui/core/Button"
7-
import InputAdornment from "@material-ui/core/InputAdornment"
8-
import Popover from "@material-ui/core/Popover"
9-
import { makeStyles } from "@material-ui/core/styles"
104
import TextField from "@material-ui/core/TextField"
115
import { Template, UpdateTemplateMeta } from "api/typesGenerated"
12-
import { OpenDropdown } from "components/DropdownArrows/DropdownArrows"
136
import { FormFooter } from "components/FormFooter/FormFooter"
147
import { Stack } from "components/Stack/Stack"
158
import { FormikContextType, FormikTouched, useFormik } from "formik"
16-
import { FC, useRef, useState } from "react"
17-
import { colors } from "theme/colors"
9+
import { FC } from "react"
1810
import {
1911
getFormHelpers,
2012
nameValidator,
@@ -25,6 +17,7 @@ import * as Yup from "yup"
2517
import i18next from "i18next"
2618
import { useTranslation } from "react-i18next"
2719
import { Maybe } from "components/Conditionals/Maybe"
20+
import { LazyIconField } from "components/IconField/LazyIconField"
2821

2922
const TTLHelperText = ({ ttl }: { ttl?: number }) => {
3023
const { t } = useTranslation("templateSettingsPage")
@@ -81,7 +74,6 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
8174
isSubmitting,
8275
initialTouched,
8376
}) => {
84-
const [isEmojiPickerOpen, setIsEmojiPickerOpen] = useState(false)
8577
const validationSchema = getValidationSchema()
8678
const form: FormikContextType<UpdateTemplateMeta> =
8779
useFormik<UpdateTemplateMeta>({
@@ -108,10 +100,6 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
108100
initialTouched,
109101
})
110102
const getFieldHelpers = getFormHelpers<UpdateTemplateMeta>(form, error)
111-
const styles = useStyles()
112-
const hasIcon = form.values.icon && form.values.icon !== ""
113-
const emojiButtonRef = useRef<HTMLButtonElement>(null)
114-
115103
const { t } = useTranslation("templateSettingsPage")
116104

117105
return (
@@ -145,65 +133,15 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
145133
rows={2}
146134
/>
147135

148-
<div className={styles.iconField}>
149-
<TextField
150-
{...getFieldHelpers("icon")}
151-
disabled={isSubmitting}
152-
fullWidth
153-
label={t("iconLabel")}
154-
variant="outlined"
155-
InputProps={{
156-
endAdornment: hasIcon ? (
157-
<InputAdornment position="end">
158-
<img
159-
alt=""
160-
src={form.values.icon}
161-
className={styles.adornment}
162-
// This prevent browser to display the ugly error icon if the
163-
// image path is wrong or user didn't finish typing the url
164-
onError={(e) => (e.currentTarget.style.display = "none")}
165-
onLoad={(e) => (e.currentTarget.style.display = "inline")}
166-
/>
167-
</InputAdornment>
168-
) : undefined,
169-
}}
170-
/>
171-
172-
<Button
173-
fullWidth
174-
ref={emojiButtonRef}
175-
variant="outlined"
176-
size="small"
177-
endIcon={<OpenDropdown />}
178-
onClick={() => {
179-
setIsEmojiPickerOpen((v) => !v)
180-
}}
181-
>
182-
{t("selectEmoji")}
183-
</Button>
184-
185-
<Popover
186-
id="emoji"
187-
open={isEmojiPickerOpen}
188-
anchorEl={emojiButtonRef.current}
189-
onClose={() => {
190-
setIsEmojiPickerOpen(false)
191-
}}
192-
>
193-
<Picker
194-
theme="dark"
195-
data={data}
196-
onEmojiSelect={(emojiData) => {
197-
// See: https://github.com/missive/emoji-mart/issues/51#issuecomment-287353222
198-
form.setFieldValue(
199-
"icon",
200-
`/emojis/${emojiData.unified.replace(/-fe0f$/, "")}.png`,
201-
)
202-
setIsEmojiPickerOpen(false)
203-
}}
204-
/>
205-
</Popover>
206-
</div>
136+
<LazyIconField
137+
{...getFieldHelpers("icon")}
138+
disabled={isSubmitting}
139+
onChange={onChangeTrimmed(form)}
140+
fullWidth
141+
label={t("form.fields.icon")}
142+
variant="outlined"
143+
onPickEmoji={(value) => form.setFieldValue("icon", value)}
144+
/>
207145

208146
<TextField
209147
{...getFieldHelpers(
@@ -244,20 +182,3 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
244182
</form>
245183
)
246184
}
247-
248-
const useStyles = makeStyles((theme) => ({
249-
"@global": {
250-
"em-emoji-picker": {
251-
"--rgb-background": theme.palette.background.paper,
252-
"--rgb-input": colors.gray[17],
253-
"--rgb-color": colors.gray[4],
254-
},
255-
},
256-
adornment: {
257-
width: theme.spacing(3),
258-
height: theme.spacing(3),
259-
},
260-
iconField: {
261-
paddingBottom: theme.spacing(0.5),
262-
},
263-
}))

site/src/testHelpers/entities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FieldError } from "api/errors"
22
import { everyOneGroup } from "util/groups"
33
import * as Types from "../api/types"
44
import * as TypesGen from "../api/typesGenerated"
5-
import { range } from "lodash"
5+
import range from "lodash/range"
66
import { Permissions } from "xServices/auth/authXService"
77

88
export const MockTemplateDAUResponse: TypesGen.TemplateDAUsResponse = {

0 commit comments

Comments
 (0)