Files
notesnook/apps/web/vite.config.ts

279 lines
8.0 KiB
TypeScript
Raw Permalink Normal View History

/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Plugin, PluginOption, ResolvedConfig, defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import svgrPlugin from "vite-plugin-svgr";
import envCompatible from "vite-plugin-env-compatible";
import { VitePWA } from "vite-plugin-pwa";
2023-06-22 13:25:56 +05:00
import autoprefixer from "autoprefixer";
import { WEB_MANIFEST } from "./web-manifest";
import { execSync } from "child_process";
import { version } from "./package.json";
import { visualizer } from "rollup-plugin-visualizer";
import { OutputPlugin } from "rollup";
2023-08-08 13:10:50 +05:00
import path from "path";
const gitHash = (() => {
try {
return execSync("git rev-parse --short HEAD").toString().trim();
} catch (e) {
return process.env.GIT_HASH || "gitless";
}
})();
// const appVersion = version.replaceAll(".", "").replace("-beta", "");
const isBeta = version.includes("-beta");
2023-06-16 19:10:02 +05:00
const isTesting =
process.env.TEST === "true" || process.env.NODE_ENV === "development";
const isDesktop = process.env.PLATFORM === "desktop";
2023-08-08 13:10:50 +05:00
const isThemeBuilder = process.env.THEME_BUILDER === "true";
const isAnalyzing = process.env.ANALYZING === "true";
export default defineConfig({
envPrefix: "NN_",
root: "src/",
2023-08-08 13:10:50 +05:00
publicDir: isThemeBuilder ? path.join(__dirname, "public") : "../public",
build: {
target: isDesktop ? "esnext" : "modules",
outDir: "../build",
minify: "esbuild",
cssMinify: true,
emptyOutDir: true,
2024-05-11 13:09:59 +05:00
sourcemap: !isDesktop,
rollupOptions: {
output: {
plugins: [emitEditorStyles()],
assetFileNames: "assets/[name]-[hash:12][extname]",
chunkFileNames: "assets/[name]-[hash:12].js",
manualChunks: (id: string) => {
if (
(id.includes("/editor/languages/") ||
2025-03-01 13:13:25 +05:00
id.includes("/html/languages/") ||
id.includes("/refractor/lang/")) &&
path.basename(id) !== "index.js"
)
return `code-lang-${path.basename(id, "js")}`;
return null;
}
}
}
},
define: {
2023-08-08 13:18:27 +05:00
APP_TITLE: `"${isThemeBuilder ? "Notesnook Theme Builder" : "Notesnook"}"`,
GIT_HASH: `"${gitHash}"`,
APP_VERSION: `"${version}"`,
PUBLIC_URL: `"${process.env.PUBLIC_URL || ""}"`,
IS_DESKTOP_APP: isDesktop,
PLATFORM: `"${process.env.PLATFORM}"`,
IS_TESTING: process.env.TEST === "true",
2024-01-31 14:31:42 +05:00
IS_BETA: isBeta,
2023-08-10 07:18:49 +05:00
IS_THEME_BUILDER: isThemeBuilder
},
logLevel: process.env.NODE_ENV === "production" ? "warn" : "info",
resolve: {
dedupe: [
"react",
"react-dom",
"@mdi/js",
"@mdi/react",
"@emotion/react",
2024-11-12 14:09:04 +05:00
"katex",
"react-modal",
"dayjs",
"@streetwriters/kysely"
],
alias: [
{
find: /\/desktop-bridge$/gm,
replacement: isDesktop
? "/desktop-bridge/index.desktop"
: "/desktop-bridge/index"
},
{
find: /\/sqlite$/gm,
replacement: isDesktop ? "/sqlite/index.desktop" : "/sqlite/index"
}
]
},
server: {
port: 3000
},
worker: {
format: "es",
rollupOptions: {
output: {
assetFileNames: "assets/[name]-[hash:12][extname]",
chunkFileNames: "assets/[name]-[hash:12].js",
inlineDynamicImports: true
}
}
},
2023-06-22 13:25:56 +05:00
css: {
postcss: {
plugins: [autoprefixer()]
}
},
plugins: [
...(isAnalyzing
? [
visualizer({
gzipSize: true,
brotliSize: true,
open: true
}) as PluginOption
]
: []),
2023-08-08 13:10:50 +05:00
...((isThemeBuilder || isDesktop) && process.env.NODE_ENV === "production"
? []
: [
VitePWA({
strategies: "injectManifest",
minify: true,
manifest: WEB_MANIFEST,
injectRegister: null,
srcDir: "",
filename: "service-worker.ts",
mode: "production",
workbox: { mode: "production" },
injectManifest: {
2025-02-13 16:01:26 +05:00
globPatterns: ["**/*.{js,css,html,wasm}", "**/Inter-*.woff2"],
globIgnores: [
"**/node_modules/**/*",
"**/code-lang-*.js",
"pdf.worker.min.js"
]
}
})
]),
react({
plugins: isTesting
? undefined
: [
[
"@swc/plugin-react-remove-properties",
{
properties: ["^data-test-id$"]
}
]
]
}),
envCompatible({
prefix: "NN_",
mountedPath: "process.env"
}),
svgrPlugin({
svgrOptions: {
icon: true,
namedExport: "ReactComponent"
// ...svgr options (https://react-svgr.com/docs/options/)
}
}),
...(isDesktop
? []
: [
prefetchPlugin({
excludeFn: (assetName) =>
assetName.includes("wa-sqlite-async") ||
!assetName.includes("wa-sqlite")
})
])
]
});
function emitEditorStyles(): OutputPlugin {
return {
name: "rollup-plugin-emit-editor-styles",
generateBundle(options, bundle) {
for (const file in bundle) {
const chunk = bundle[file];
if (
chunk.type === "asset" &&
chunk.fileName.endsWith(".css") &&
typeof chunk.source === "string" &&
(chunk.source.includes("KaTeX_Fraktur-Bold-") ||
chunk.source.includes("Hack typeface"))
) {
this.emitFile({
type: "asset",
fileName: "assets/editor-styles.css",
name: "editor-styles.css",
source: chunk.source
});
}
}
}
};
}
function prefetchPlugin(options?: {
excludeFn?: (assetName: string) => boolean;
}): Plugin {
let config: ResolvedConfig;
return {
name: "vite-plugin-bundle-prefetch",
apply: "build",
configResolved(resolvedConfig: ResolvedConfig) {
// store the resolved config
config = resolvedConfig;
},
transformIndexHtml(
html: string,
ctx: {
path: string;
filename: string;
bundle?: import("rollup").OutputBundle;
chunk?: import("rollup").OutputChunk;
}
) {
const bundles = Object.keys(ctx.bundle ?? {});
const isLegacy = bundles.some((bundle) => bundle.includes("legacy"));
if (isLegacy) {
//legacy build won't add prefetch
return html;
}
// remove map files
let modernBundles = bundles.filter(
(bundle) => bundle.endsWith(".map") === false
);
const excludeFn = options?.excludeFn;
if (excludeFn) {
modernBundles = modernBundles.filter((bundle) => !excludeFn(bundle));
}
// Remove existing files and concatenate them into link tags
const prefechBundlesString = modernBundles
.filter((bundle) => html.includes(bundle) === false)
.map((bundle) => `<link rel="prefetch" href="${config.base}${bundle}">`)
.join("\n");
// Use regular expression to get the content within <head> </head>
const headContent = html.match(/<head>([\s\S]*)<\/head>/)?.[1] ?? "";
// Insert the content of prefetch into the head
const newHeadContent = `${headContent}${prefechBundlesString}`;
// Replace the original head
html = html.replace(
/<head>([\s\S]*)<\/head>/,
`<head>${newHeadContent}</head>`
);
return html;
}
};
}