1import frameworkUI from "@framework/ui/vite";
2import vue from "@vitejs/plugin-vue";
3import vueJsx from "@vitejs/plugin-vue-jsx";
4import path from "path";
5import { defineConfig } from "vite";
6import { VitePWA } from "vite-plugin-pwa";
7import {
8 getLocalFrappeUIDevConfig,
9 importFrappeUIPlugin,
10} from "./vite-helpers";
11
12export default defineConfig(async ({ mode }) => {
13 const { useLocalFrappeUI, localFrappeUIAliases } = getLocalFrappeUIDevConfig({
14 mode,
15 rootDir: __dirname,
16 });
17
18 const frappeui = await importFrappeUIPlugin({ useLocalFrappeUI });
19 const config = {
20 plugins: [
21 frappeui({
22 frappeProxy: true,
23 lucideIcons: true,
24 jinjaBootData: true,
25 buildConfig: {
26 outDir: `../opendesk/public/desk`,
27 emptyOutDir: true,
28 indexHtmlPath: "../opendesk/www/opendesk/index.html",
29 },
30 frappeTypes: {
31 input: {
32 opendesk: [
33 "od_ticket_status",
34 "od_ticket",
35 "od_service_holiday_list",
36 "od_service_level_agreement",
37 "od_agent",
38 "od_team",
39 "od_customer",
40 ],
41 frappe: ["assignment_rule", "contact"],
42 },
43 },
44 }),
45 frameworkUI(),
46
47 vue(),
48 vueJsx(),
49 VitePWA({
50 registerType: "autoUpdate",
51 devOptions: {
52 enabled: true,
53 },
54 workbox: {
55 cleanupOutdatedCaches: true,
56 maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
57 },
58 manifest: {
59 display: "standalone",
60 name: "Opendesk",
61 short_name: "Opendesk",
62 start_url: "/opendesk",
63 description:
64 "Modern, Streamlined, Free and Open Source Customer Service Software",
65 icons: [
66 {
67 src: "/assets/opendesk/desk/manifest/manifest-icon-192.maskable.png",
68 sizes: "192x192",
69 type: "image/png",
70 purpose: "any",
71 },
72 {
73 src: "/assets/opendesk/desk/manifest/manifest-icon-192.maskable.png",
74 sizes: "192x192",
75 type: "image/png",
76 purpose: "maskable",
77 },
78 {
79 src: "/assets/opendesk/desk/manifest/manifest-icon-512.maskable.png",
80 sizes: "512x512",
81 type: "image/png",
82 purpose: "any",
83 },
84 {
85 src: "/assets/opendesk/desk/manifest/manifest-icon-512.maskable.png",
86 sizes: "512x512",
87 type: "image/png",
88 purpose: "maskable",
89 },
90 ],
91 },
92 }),
93 ],
94 server: {
95 allowedHosts: true,
96 fs: {
97 // ".." = apps/opendesk; "../.." = apps/, so the linked @framework/ui
98 // (apps/frappe/ui) can be served from source in dev.
99 allow: ["..", "../.."],
100 },
101 },
102 resolve: {
103 alias: {
104 "@": path.resolve(__dirname, "src"),
105 "tailwind.config.js": path.resolve(__dirname, "tailwind.config.js"),
106 // @framework/ui still imports the `frappe-ui/editor-style.css` subpath,
107 // dropped in frappe-ui 1.0.0-beta.63 (the editor entrypoint pulls its
108 // own stylesheet now). Point it at the real file until frappe drops it.
109 "frappe-ui/editor-style.css": path.resolve(
110 __dirname,
111 "node_modules/frappe-ui/src/molecules/editor/style.css"
112 ),
113 // ...localFrappeUIAliases,
114 },
115 // frappe-ui is served from source (excluded from optimizeDeps) and the
116 // submodule ships its own node_modules with older tiptap/ProseMirror.
117 // Force a single copy of each so the editor doesn't load two
118 // prosemirror-state instances (RangeError: different instances of a keyed plugin).
119 dedupe: [
120 // @framework/ui imports from vue/frappe-ui; force a single instance of
121 // each so its Combobox shares opendesk's frappe-ui, not a second copy.
122 // vue-router and dompurify are peers of @framework/ui, so they have
123 // to come from opendesk's copies
124 "vue",
125 "vue-router",
126 "frappe-ui",
127 // studio's NewTicketForm imports it from outside desk/
128 "@framework/ui",
129 "dompurify",
130 "reka-ui",
131 "@tiptap/core",
132 "@tiptap/pm",
133 // shared/ imports these from outside desk/
134 "@tiptap/extension-table",
135 "@tiptap/extension-text-align",
136 "@tiptap/extension-text-style",
137 "@tiptap/starter-kit",
138 "prosemirror-state",
139 "prosemirror-model",
140 "prosemirror-transform",
141 "prosemirror-view",
142 "prosemirror-keymap",
143 "prosemirror-commands",
144 "prosemirror-history",
145 "prosemirror-gapcursor",
146 "prosemirror-tables",
147 // shared/ imports it from outside desk/
148 "vuedraggable",
149 ],
150 },
151 optimizeDeps: {
152 include: [
153 "tailwind.config.js",
154 "prosemirror-state",
155 "prosemirror-view",
156 "prosemirror-gapcursor",
157 "prosemirror-tables",
158 "lowlight",
159 "interactjs",
160 ],
161 exclude: ["frappe-ui", "@framework/ui", "@opendesk/shared"],
162 },
163 };
164 return config;
165});
166