Skip to content

Commit e754f89

Browse files
hanspageltommoorvio
authored
Replace Webpack with Vite (outline#4765)
Co-authored-by: Tom Moor <[email protected]> Co-authored-by: Vio <[email protected]>
1 parent 490d05b commit e754f89

40 files changed

+1689
-3608
lines changed

.circleci/config.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ jobs:
9898
- restore_cache:
9999
key: dependency-cache-{{ checksum "package.json" }}
100100
- run:
101-
name: build-webpack
102-
command: yarn build:webpack
101+
name: build-vite
102+
command: yarn vite:build
103+
- run:
104+
name: Send bundle stats to RelativeCI
105+
command: npx relative-ci-agent
103106
build-image:
104107
executor: docker-publisher
105108
steps:

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ fakes3/*
1111
.idea
1212
*.pem
1313
*.key
14-
*.cert
14+
*.cert

app/components/AuthenticatedLayout.tsx

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,12 @@ import {
2525
import Fade from "./Fade";
2626

2727
const DocumentHistory = React.lazy(
28-
() =>
29-
import(
30-
/* webpackChunkName: "document-history" */
31-
"~/scenes/Document/components/History"
32-
)
28+
() => import("~/scenes/Document/components/History")
3329
);
3430
const DocumentInsights = React.lazy(
35-
() =>
36-
import(
37-
/* webpackChunkName: "document-insights" */
38-
"~/scenes/Document/components/Insights"
39-
)
40-
);
41-
const CommandBar = React.lazy(
42-
() =>
43-
import(
44-
/* webpackChunkName: "command-bar" */
45-
"~/components/CommandBar"
46-
)
31+
() => import("~/scenes/Document/components/Insights")
4732
);
33+
const CommandBar = React.lazy(() => import("~/components/CommandBar"));
4834

4935
const AuthenticatedLayout: React.FC = ({ children }) => {
5036
const { ui, auth } = useStores();

app/components/Collaborators.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as React from "react";
44
import { useTranslation } from "react-i18next";
55
import { usePopoverState, PopoverDisclosure } from "reakit/Popover";
66
import Document from "~/models/Document";
7-
import { AvatarWithPresence } from "~/components/Avatar";
7+
import AvatarWithPresence from "~/components/Avatar/AvatarWithPresence";
88
import DocumentViews from "~/components/DocumentViews";
99
import Facepile from "~/components/Facepile";
1010
import NudeButton from "~/components/NudeButton";

app/components/Editor.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,7 @@ import { sharedDocumentPath } from "~/utils/routeHelpers";
3030
import { isHash } from "~/utils/urls";
3131
import DocumentBreadcrumb from "./DocumentBreadcrumb";
3232

33-
const LazyLoadedEditor = React.lazy(
34-
() =>
35-
import(
36-
/* webpackChunkName: "preload-shared-editor" */
37-
"~/editor"
38-
)
39-
);
33+
const LazyLoadedEditor = React.lazy(() => import("~/editor"));
4034

4135
export type Props = Optional<
4236
EditorProps,

app/components/ErrorBoundary.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ErrorBoundary extends React.Component<Props> {
3030
if (
3131
this.props.reloadOnChunkMissing &&
3232
error.message &&
33-
error.message.match(/chunk/)
33+
error.message.match(/dynamically imported module/)
3434
) {
3535
// If the editor bundle fails to load then reload the entire window. This
3636
// can happen if a deploy happens between the user loading the initial JS
@@ -60,7 +60,9 @@ class ErrorBoundary extends React.Component<Props> {
6060
if (this.error) {
6161
const error = this.error;
6262
const isReported = !!env.SENTRY_DSN && isCloudHosted;
63-
const isChunkError = this.error.message.match(/chunk/);
63+
const isChunkError = this.error.message.match(
64+
/dynamically imported module/
65+
);
6466

6567
if (isChunkError) {
6668
return (

app/components/IconPicker.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,7 @@ const style = {
5353
};
5454

5555
const TwitterPicker = React.lazy(
56-
() =>
57-
import(
58-
/* webpackChunkName: "twitter-picker" */
59-
"react-color/lib/components/twitter/Twitter"
60-
)
56+
() => import("react-color/lib/components/twitter/Twitter")
6157
);
6258

6359
export const icons = {

app/components/TableFromParams.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ import scrollIntoView from "smooth-scroll-into-view-if-needed";
55
import useQuery from "~/hooks/useQuery";
66
import type { Props } from "./Table";
77

8-
const Table = React.lazy(
9-
() =>
10-
import(
11-
/* webpackChunkName: "table" */
12-
"~/components/Table"
13-
)
14-
);
8+
const Table = React.lazy(() => import("~/components/Table"));
159

1610
const TableFromParams = (
1711
props: Omit<Props, "onChangeSort" | "onChangePage" | "topRef">

app/components/Time.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
import { formatDistanceToNow } from "date-fns";
22
import * as React from "react";
33

4-
const LocaleTime = React.lazy(
5-
() =>
6-
import(
7-
/* webpackChunkName: "locale-time" */
8-
"~/components/LocaleTime"
9-
)
10-
);
4+
const LocaleTime = React.lazy(() => import("~/components/LocaleTime"));
115

126
type Props = React.ComponentProps<typeof LocaleTime> & {
137
onClick?: () => void;

app/index.tsx

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
// eslint-disable-next-line import/no-unresolved
2+
import "vite/modulepreload-polyfill";
13
import "focus-visible";
4+
import "setimmediate";
25
import { LazyMotion } from "framer-motion";
36
import { KBarProvider } from "kbar";
47
import { Provider } from "mobx-react";
@@ -35,33 +38,6 @@ if (env.SENTRY_DSN) {
3538
initSentry(history);
3639
}
3740

38-
if ("serviceWorker" in window.navigator) {
39-
window.addEventListener("load", () => {
40-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1097616
41-
// In some rare (<0.1% of cases) this call can return `undefined`
42-
const maybePromise = window.navigator.serviceWorker.register(
43-
"/static/service-worker.js",
44-
{
45-
scope: "/",
46-
}
47-
);
48-
49-
if (maybePromise?.then) {
50-
maybePromise
51-
.then((registration) => {
52-
Logger.debug("lifecycle", "SW registered: ", registration);
53-
})
54-
.catch((registrationError) => {
55-
Logger.debug(
56-
"lifecycle",
57-
"SW registration failed: ",
58-
registrationError
59-
);
60-
});
61-
}
62-
});
63-
}
64-
6541
// Make sure to return the specific export containing the feature bundle.
6642
const loadFeatures = () => import("./utils/motion").then((res) => res.default);
6743

@@ -116,13 +92,38 @@ window.addEventListener("load", async () => {
11692
return;
11793
}
11894
// https://github.com/googleanalytics/autotrack/issues/137#issuecomment-305890099
119-
await import(
120-
/* webpackChunkName: "autotrack" */
121-
"autotrack/autotrack.js"
122-
);
95+
await import("autotrack/autotrack.js");
12396
window.ga("require", "outboundLinkTracker");
12497
window.ga("require", "urlChangeTracker");
12598
window.ga("require", "eventTracker", {
12699
attributePrefix: "data-",
127100
});
128101
});
102+
103+
if ("serviceWorker" in navigator) {
104+
window.addEventListener("load", () => {
105+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1097616
106+
// In some rare (<0.1% of cases) this call can return `undefined`
107+
const maybePromise = navigator.serviceWorker.register("/static/sw.js", {
108+
scope: "/",
109+
});
110+
111+
if (maybePromise?.then) {
112+
maybePromise
113+
.then((registration) => {
114+
Logger.debug(
115+
"lifecycle",
116+
"[ServiceWorker] Registered.",
117+
registration
118+
);
119+
})
120+
.catch((registrationError) => {
121+
Logger.debug(
122+
"lifecycle",
123+
"[ServiceWorker] Registration failed.",
124+
registrationError
125+
);
126+
});
127+
}
128+
});
129+
}

app/models/Collection.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
NavigationNode,
77
} from "@shared/types";
88
import { sortNavigationNodes } from "@shared/utils/collections";
9-
import CollectionsStore from "~/stores/CollectionsStore";
9+
import type CollectionsStore from "~/stores/CollectionsStore";
1010
import Document from "~/models/Document";
1111
import ParanoidModel from "~/models/ParanoidModel";
1212
import { client } from "~/utils/ApiClient";
@@ -18,9 +18,6 @@ export default class Collection extends ParanoidModel {
1818
@observable
1919
isSaving: boolean;
2020

21-
@observable
22-
isLoadingUsers: boolean;
23-
2421
@Field
2522
@observable
2623
id: string;

app/routes/authenticated.tsx

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,11 @@ import useCurrentTeam from "~/hooks/useCurrentTeam";
1616
import usePolicy from "~/hooks/usePolicy";
1717
import { matchDocumentSlug as slug } from "~/utils/routeHelpers";
1818

19-
const SettingsRoutes = React.lazy(
20-
() =>
21-
import(
22-
/* webpackChunkName: "settings" */
23-
"./settings"
24-
)
25-
);
26-
const Document = React.lazy(
27-
() =>
28-
import(
29-
/* webpackChunkName: "preload-document" */
30-
"~/scenes/Document"
31-
)
32-
);
33-
const Collection = React.lazy(
34-
() =>
35-
import(
36-
/* webpackChunkName: "collection" */
37-
"~/scenes/Collection"
38-
)
39-
);
40-
const Home = React.lazy(
41-
() =>
42-
import(
43-
/* webpackChunkName: "home" */
44-
"~/scenes/Home"
45-
)
46-
);
47-
const Search = React.lazy(
48-
() =>
49-
import(
50-
/* webpackChunkName: "search" */
51-
"~/scenes/Search"
52-
)
53-
);
19+
const SettingsRoutes = React.lazy(() => import("./settings"));
20+
const Document = React.lazy(() => import("~/scenes/Document"));
21+
const Collection = React.lazy(() => import("~/scenes/Collection"));
22+
const Home = React.lazy(() => import("~/scenes/Home"));
23+
const Search = React.lazy(() => import("~/scenes/Search"));
5424

5525
const RedirectDocument = ({
5626
match,

app/routes/index.tsx

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,11 @@ import FullscreenLoading from "~/components/FullscreenLoading";
66
import Route from "~/components/ProfiledRoute";
77
import { matchDocumentSlug as slug } from "~/utils/routeHelpers";
88

9-
const Authenticated = React.lazy(
10-
() =>
11-
import(
12-
/* webpackChunkName: "preload-authenticated" */
13-
"~/components/Authenticated"
14-
)
15-
);
16-
const AuthenticatedRoutes = React.lazy(
17-
() =>
18-
import(
19-
/* webpackChunkName: "preload-authenticated-routes" */
20-
"./authenticated"
21-
)
22-
);
23-
const SharedDocument = React.lazy(
24-
() =>
25-
import(
26-
/* webpackChunkName: "shared-document" */
27-
"~/scenes/Document/Shared"
28-
)
29-
);
30-
const Login = React.lazy(
31-
() =>
32-
import(
33-
/* webpackChunkName: "login" */
34-
"~/scenes/Login"
35-
)
36-
);
37-
const Logout = React.lazy(
38-
() =>
39-
import(
40-
/* webpackChunkName: "logout" */
41-
"~/scenes/Logout"
42-
)
43-
);
9+
const Authenticated = React.lazy(() => import("~/components/Authenticated"));
10+
const AuthenticatedRoutes = React.lazy(() => import("./authenticated"));
11+
const SharedDocument = React.lazy(() => import("~/scenes/Document/Shared"));
12+
const Login = React.lazy(() => import("~/scenes/Login"));
13+
const Logout = React.lazy(() => import("~/scenes/Logout"));
4414

4515
export default function Routes() {
4616
return (
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
import * as React from "react";
22

3-
const MultiplayerEditor = React.lazy(
4-
() =>
5-
import(
6-
/* webpackChunkName: "preload-multiplayer-editor" */
7-
"./MultiplayerEditor"
8-
)
9-
);
3+
const MultiplayerEditor = React.lazy(() => import("./MultiplayerEditor"));
104

115
export default MultiplayerEditor;

app/stores/BaseStore.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import invariant from "invariant";
2-
import { orderBy } from "lodash";
2+
import { lowerFirst, orderBy } from "lodash";
33
import { observable, action, computed, runInAction } from "mobx";
44
import { Class } from "utility-types";
55
import RootStore from "~/stores/RootStore";
@@ -20,10 +20,6 @@ export enum RPCAction {
2020

2121
type FetchPageParams = PaginationParams & Record<string, any>;
2222

23-
function modelNameFromClassName(string: string) {
24-
return string.charAt(0).toLowerCase() + string.slice(1);
25-
}
26-
2723
export const DEFAULT_PAGINATION_LIMIT = 25;
2824

2925
export const PAGINATION_SYMBOL = Symbol.for("pagination");
@@ -61,7 +57,7 @@ export default abstract class BaseStore<T extends BaseModel> {
6157
constructor(rootStore: RootStore, model: Class<T>) {
6258
this.rootStore = rootStore;
6359
this.model = model;
64-
this.modelName = modelNameFromClassName(model.name);
60+
this.modelName = lowerFirst(model.name);
6561

6662
if (!this.apiEndpoint) {
6763
this.apiEndpoint = `${this.modelName}s`;

app/typings/window.d.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
declare global {
2-
interface NodeRequire {
3-
/** A special feature supported by webpack's compiler that allows you to get all matching modules starting from some base directory. */
4-
context: (
5-
directory: string,
6-
useSubdirectories: boolean,
7-
regExp: RegExp
8-
) => any;
2+
interface ImportMeta {
3+
/**
4+
* A special feature that allows you to get all matching modules starting from some base directory.
5+
*/
6+
glob: (pattern: string, option?: { eager: boolean }) => any;
97
}
108

119
interface Window {

0 commit comments

Comments
 (0)