web: fix service worker to allow Notesnook to behave as a PWA again (#2905)

* web: make service worker work again

* web: only enable sourcemap during dev
This commit is contained in:
Abdullah Atta
2023-07-12 06:51:14 +05:00
committed by GitHub
parent df5cbacc8a
commit 5854a3eef5
37 changed files with 1343 additions and 355 deletions

View File

@@ -1,47 +0,0 @@
const { execSync } = require("child_process");
const { cpus, networkInterfaces } = require("os");
const { version } = require("./package.json");
const ip = require("ip");
const NUM_CPUS = cpus().length;
const IS_CI = process.env.CI;
const gitHash = execSync("git rev-parse --short HEAD").toString().trim();
const APP_VERSION = version.replaceAll(".", "");
console.log("App version:", APP_VERSION);
console.log("Ip address:", ip.address());
module.exports = {
beta: {
REACT_APP_BETA: true
},
test: {
TEST_ALL: true
},
all: {
UV_THREADPOOL_SIZE: IS_CI ? NUM_CPUS : 2,
GENERATE_SOURCEMAP: process.env.NODE_ENV === "development",
// INLINE_RUNTIME_CHUNK: false,
// DISABLE_ESLINT_PLUGIN: true,
REACT_APP_GIT_HASH: gitHash,
REACT_APP_VERSION: APP_VERSION
},
dev: {
REACT_APP_LOCALHOST: ip.address()
},
web: {
REACT_APP_PLATFORM: "web"
},
debug: {
PWDEBUG: 1,
DEBUG: "pw:api"
},
silent: {
REACT_APP_TEST: true
// DISABLE_ESLINT_PLUGIN: "true"
// FAST_REFRESH: "false",
// BROWSER: "none"
},
desktop: {
// BROWSER: "none",
REACT_APP_PLATFORM: "desktop"
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -82,8 +82,8 @@
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"cross-env": "^7.0.3",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"env-cmd": "^10.1.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"find-process": "^1.4.4", "find-process": "^1.4.4",
"happy-dom": "^8.9.0", "happy-dom": "^8.9.0",
@@ -111,13 +111,13 @@
"@types/react-dom@>17": "17.0.2" "@types/react-dom@>17": "17.0.2"
}, },
"scripts": { "scripts": {
"start": "env-cmd -e all,dev,web vite", "start": "cross-env PLATFORM=web vite",
"start:desktop": "env-cmd -e all,desktop vite", "start:desktop": "cross-env PLATFORM=desktop vite",
"start:test": "serve -s build/ -p 3000", "start:test": "serve -s build/ -p 3000",
"build": "env-cmd -e all,web vite build", "build": "cross-env PLATFORM=web vite build",
"build:test": "env-cmd -e all,dev,web,silent vite build", "build:test": "cross-env PLATFORM=web TEST=true vite build",
"build:beta": "env-cmd -e all,web,beta vite build", "build:beta": "cross-env PLATFORM=web BETA=true vite build",
"build:desktop": "env-cmd -e all,desktop vite build", "build:desktop": "cross-env PLATFORM=desktop vite build",
"test": "playwright test -u" "test": "playwright test -u"
}, },
"browserslist": { "browserslist": {

View File

@@ -39,7 +39,7 @@ import {
showOnboardingDialog showOnboardingDialog
} from "./common/dialog-controller"; } from "./common/dialog-controller";
import useSystemTheme from "./hooks/use-system-theme"; import useSystemTheme from "./hooks/use-system-theme";
import { isTesting } from "./utils/platform";
import { updateStatus, removeStatus, getStatus } from "./hooks/use-status"; import { updateStatus, removeStatus, getStatus } from "./hooks/use-status";
import { showToast } from "./utils/toast"; import { showToast } from "./utils/toast";
import { interruptedOnboarding } from "./dialogs/onboarding-dialog"; import { interruptedOnboarding } from "./dialogs/onboarding-dialog";
@@ -199,7 +199,7 @@ export default function AppEffects({ setShow }: AppEffectsProps) {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!dialogAnnouncements.length || isTesting()) return; if (!dialogAnnouncements.length || IS_TESTING) return;
(async () => { (async () => {
await showAnnouncementDialog(dialogAnnouncements[0]); await showAnnouncementDialog(dialogAnnouncements[0]);
})(); })();

View File

@@ -111,11 +111,7 @@ function SuspenseLoader<TComponent extends React.JSXElementConstructor<any>>({
props: any props: any
) => React.ReactComponentElement<any, any>; ) => React.ReactComponentElement<any, any>;
return ( return (
<Suspense <Suspense fallback={IS_DESKTOP_APP ? null : fallback}>
fallback={
import.meta.env.REACT_APP_PLATFORM === "desktop" ? null : fallback
}
>
<Component {...props} /> <Component {...props} />
</Suspense> </Suspense>
); );

View File

@@ -47,7 +47,7 @@ async function initializeDatabase(persistence: DatabasePersistence) {
FS, FS,
new Compressor() new Compressor()
); );
// if (isTesting()) { // if (IS_TESTING) {
// } else { // } else {
// db.host({ // db.host({

View File

@@ -27,7 +27,7 @@ import Config from "../utils/config";
import { hashNavigate, getCurrentHash } from "../navigation"; import { hashNavigate, getCurrentHash } from "../navigation";
import { db } from "./db"; import { db } from "./db";
import { sanitizeFilename } from "@notesnook/common"; import { sanitizeFilename } from "@notesnook/common";
import { isDesktop, isTesting } from "../utils/platform";
import { store as userstore } from "../stores/user-store"; import { store as userstore } from "../stores/user-store";
import FileSaver from "file-saver"; import FileSaver from "file-saver";
import { showToast } from "../utils/toast"; import { showToast } from "../utils/toast";
@@ -66,7 +66,7 @@ export const CREATE_BUTTON_MAP = {
export async function introduceFeatures() { export async function introduceFeatures() {
const hash = getCurrentHash().replace("#", ""); const hash = getCurrentHash().replace("#", "");
if (!!hash || isTesting()) return; if (!!hash || IS_TESTING) return;
const features = []; const features = [];
for (let feature of features) { for (let feature of features) {
if (!Config.get(`feature:${feature}`)) { if (!Config.get(`feature:${feature}`)) {
@@ -95,7 +95,7 @@ export async function createBackup() {
const filename = sanitizeFilename(`notesnook-backup-${getFormattedDate()}`); const filename = sanitizeFilename(`notesnook-backup-${getFormattedDate()}`);
const ext = "nnbackup"; const ext = "nnbackup";
if (isDesktop()) { if (IS_DESKTOP_APP) {
const directory = Config.get( const directory = Config.get(
"backupStorageLocation", "backupStorageLocation",
PATHS.backupsDirectory PATHS.backupsDirectory
@@ -189,7 +189,7 @@ export function totalSubscriptionConsumed(user) {
} }
export async function showUpgradeReminderDialogs() { export async function showUpgradeReminderDialogs() {
if (isTesting()) return; if (IS_TESTING) return;
const user = userstore.get().user; const user = userstore.get().user;
if (!user || !user.subscription || user.subscription?.expiry === 0) return; if (!user || !user.subscription || user.subscription?.expiry === 0) return;

View File

@@ -25,7 +25,7 @@ import { Backup, User, Email, Warn, Icon } from "../components/icons";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { showBuyDialog, showRecoveryKeyDialog } from "./dialog-controller"; import { showBuyDialog, showRecoveryKeyDialog } from "./dialog-controller";
import { hardNavigate, hashNavigate } from "../navigation"; import { hardNavigate, hashNavigate } from "../navigation";
import { isDesktop, isTesting } from "../utils/platform";
import { isUserPremium } from "../hooks/use-is-user-premium"; import { isUserPremium } from "../hooks/use-is-user-premium";
import { showToast } from "../utils/toast"; import { showToast } from "../utils/toast";
import { TaskScheduler } from "../utils/task-scheduler"; import { TaskScheduler } from "../utils/task-scheduler";
@@ -176,9 +176,9 @@ function isIgnored(key: keyof typeof NoticesData) {
var openedToast: { hide: () => void } | null = null; var openedToast: { hide: () => void } | null = null;
async function saveBackup() { async function saveBackup() {
if (isDesktop()) { if (IS_DESKTOP_APP) {
await createBackup(); await createBackup();
} else if (isUserPremium() && !isTesting()) { } else if (isUserPremium() && !IS_TESTING) {
if (openedToast !== null) return; if (openedToast !== null) return;
openedToast = showToast( openedToast = showToast(
"success", "success",

View File

@@ -85,7 +85,7 @@ type TipTapProps = {
fontFamily: string; fontFamily: string;
}; };
const SAVE_INTERVAL = import.meta.env.REACT_APP_TEST ? 100 : 300; const SAVE_INTERVAL = IS_TESTING ? 100 : 300;
function save( function save(
sessionId: number, sessionId: number,

View File

@@ -48,7 +48,6 @@ import { useStore as useUserStore } from "../../stores/user-store";
import { useStore as useThemeStore } from "../../stores/theme-store"; import { useStore as useThemeStore } from "../../stores/theme-store";
import useLocation from "../../hooks/use-location"; import useLocation from "../../hooks/use-location";
import { FlexScrollContainer } from "../scroll-container"; import { FlexScrollContainer } from "../scroll-container";
import { isDesktop } from "../../utils/platform";
type Route = { type Route = {
title: string; title: string;
@@ -192,7 +191,7 @@ function NavigationMenu(props: NavigationMenuProps) {
))} ))}
{colors.map((color, index) => ( {colors.map((color, index) => (
<NavigationItem <NavigationItem
animate={!isDesktop()} animate={!IS_DESKTOP_APP}
index={index} index={index}
isTablet={isTablet} isTablet={isTablet}
key={color.id} key={color.id}
@@ -221,7 +220,7 @@ function NavigationMenu(props: NavigationMenuProps) {
/> />
{shortcuts.map((item, index) => ( {shortcuts.map((item, index) => (
<NavigationItem <NavigationItem
animate={!isDesktop()} animate={!IS_DESKTOP_APP}
index={colors.length - 1 + index} index={colors.length - 1 + index}
isTablet={isTablet} isTablet={isTablet}
key={item.id} key={item.id}

View File

@@ -31,20 +31,17 @@ import {
PricingInfo PricingInfo
} from "./types"; } from "./types";
// const isDev = false; // import.meta.env.NODE_ENV === "development"; // const isDev = false; // import.meta.env.DEV;
// const VENDOR_ID = isDev ? 1506 : 128190; // const VENDOR_ID = isDev ? 1506 : 128190;
const PADDLE_ORIGIN = const PADDLE_ORIGIN = import.meta.env.DEV
import.meta.env.NODE_ENV === "development" ? "https://sandbox-buy.paddle.com"
? "https://sandbox-buy.paddle.com" : "https://buy.paddle.com";
: "https://buy.paddle.com"; const CHECKOUT_CREATE_ORIGIN = import.meta.env.DEV
const CHECKOUT_CREATE_ORIGIN = ? "https://sandbox-create-checkout.paddle.com"
import.meta.env.NODE_ENV === "development" : "https://create-checkout.paddle.com";
? "https://sandbox-create-checkout.paddle.com" const CHECKOUT_SERVICE_ORIGIN = import.meta.env.DEV
: "https://create-checkout.paddle.com"; ? "https://sandbox-checkout-service.paddle.com"
const CHECKOUT_SERVICE_ORIGIN = : "https://checkout-service.paddle.com";
import.meta.env.NODE_ENV === "development"
? "https://sandbox-checkout-service.paddle.com"
: "https://checkout-service.paddle.com";
const SUBSCRIBED_EVENTS: PaddleEvents[] = [ const SUBSCRIBED_EVENTS: PaddleEvents[] = [
PaddleEvents["Checkout.Loaded"], PaddleEvents["Checkout.Loaded"],

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { isTesting } from "../../utils/platform";
import { Period, Plan } from "./types"; import { Period, Plan } from "./types";
type PlanMetadata = { type PlanMetadata = {
@@ -32,7 +32,7 @@ export const DEFAULT_PLANS: Plan[] = [
country: "PK", country: "PK",
currency: "USD", currency: "USD",
discount: 0, discount: 0,
id: import.meta.env.NODE_ENV === "development" ? "9822" : "648884", id: import.meta.env.DEV ? "9822" : "648884",
price: { gross: 4.49, net: 0, tax: 0 } price: { gross: 4.49, net: 0, tax: 0 }
}, },
{ {
@@ -40,7 +40,7 @@ export const DEFAULT_PLANS: Plan[] = [
country: "PK", country: "PK",
currency: "USD", currency: "USD",
discount: 0, discount: 0,
id: import.meta.env.NODE_ENV === "development" ? "50305" : "658759", id: import.meta.env.DEV ? "50305" : "658759",
price: { gross: 49.99, net: 0, tax: 0 } price: { gross: 49.99, net: 0, tax: 0 }
} }
]; ];
@@ -52,8 +52,7 @@ export const PLAN_METADATA: Record<Period, PlanMetadata> = {
let CACHED_PLANS: Plan[]; let CACHED_PLANS: Plan[];
export async function getPlans(): Promise<Plan[] | null> { export async function getPlans(): Promise<Plan[] | null> {
if (isTesting() || import.meta.env.NODE_ENV === "development") if (IS_TESTING || import.meta.env.DEV) return DEFAULT_PLANS;
return DEFAULT_PLANS;
if (CACHED_PLANS) return CACHED_PLANS; if (CACHED_PLANS) return CACHED_PLANS;
const url = `https://notesnook.com/api/v1/prices/products/web`; const url = `https://notesnook.com/api/v1/prices/products/web`;

View File

@@ -22,7 +22,7 @@ import Dialog from "../components/dialog";
import { getHomeRoute, hardNavigate } from "../navigation"; import { getHomeRoute, hardNavigate } from "../navigation";
import { appVersion } from "../utils/version"; import { appVersion } from "../utils/version";
import Config from "../utils/config"; import Config from "../utils/config";
import { isTesting } from "../utils/platform";
import { useEffect } from "react"; import { useEffect } from "react";
import { ArrowRight, Checkmark, Icon, Warn } from "../components/icons"; import { ArrowRight, Checkmark, Icon, Warn } from "../components/icons";
@@ -106,7 +106,7 @@ const features: Record<FeatureKeys, Feature> = {
appVersion.isBeta || Config.has((k) => k.endsWith(":highlights")); appVersion.isBeta || Config.has((k) => k.endsWith(":highlights"));
if (!hasShownAny) Config.set(key, true); if (!hasShownAny) Config.set(key, true);
return hasShownAny && !isTesting() && !hasShownBefore; return hasShownAny && !IS_TESTING && !hasShownBefore;
} }
} }
}; };

View File

@@ -24,7 +24,7 @@ import { createBackup } from "../common";
import { db } from "../common/db"; import { db } from "../common/db";
import { Perform } from "../common/dialog-controller"; import { Perform } from "../common/dialog-controller";
import { TaskManager } from "../common/task-manager"; import { TaskManager } from "../common/task-manager";
import { isDesktop } from "../utils/platform";
import Dialog from "../components/dialog"; import Dialog from "../components/dialog";
type MigrationProgressEvent = { type MigrationProgressEvent = {
@@ -74,7 +74,7 @@ export default function MigrationDialog(props: MigrationDialogProps) {
}, [props]); }, [props]);
useEffect(() => { useEffect(() => {
if (isDesktop()) { if (IS_DESKTOP_APP) {
(async () => { (async () => {
await startMigration(); await startMigration();
})(); })();
@@ -115,7 +115,7 @@ export default function MigrationDialog(props: MigrationDialogProps) {
); );
} }
if (isDesktop() || isProcessing) return null; if (IS_DESKTOP_APP || isProcessing) return null;
return ( return (
<Dialog <Dialog

View File

@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { SettingsGroup } from "./types"; import { SettingsGroup } from "./types";
import { useStore as useSettingStore } from "../../stores/setting-store"; import { useStore as useSettingStore } from "../../stores/setting-store";
import { useStore as useThemeStore } from "../../stores/theme-store"; import { useStore as useThemeStore } from "../../stores/theme-store";
import { isDesktop } from "../../utils/platform";
import { AccentColors } from "./components/accent-colors"; import { AccentColors } from "./components/accent-colors";
export const AppearanceSettings: SettingsGroup[] = [ export const AppearanceSettings: SettingsGroup[] = [
@@ -72,7 +72,7 @@ export const AppearanceSettings: SettingsGroup[] = [
key: "zoom-factor", key: "zoom-factor",
title: "Zoom factor", title: "Zoom factor",
description: "Zoom in or out the app content.", description: "Zoom in or out the app content.",
isHidden: () => !isDesktop(), isHidden: () => !IS_DESKTOP_APP,
onStateChange: (listener) => onStateChange: (listener) =>
useThemeStore.subscribe( useThemeStore.subscribe(
(s) => [s.theme, s.followSystemTheme], (s) => [s.theme, s.followSystemTheme],

View File

@@ -25,7 +25,7 @@ import { isUserPremium } from "../../hooks/use-is-user-premium";
import { createBackup, importBackup, verifyAccount } from "../../common"; import { createBackup, importBackup, verifyAccount } from "../../common";
import { db } from "../../common/db"; import { db } from "../../common/db";
import { exportNotes } from "../../common/export"; import { exportNotes } from "../../common/export";
import { isDesktop, isTesting } from "../../utils/platform";
import { desktop } from "../../common/desktop-bridge"; import { desktop } from "../../common/desktop-bridge";
import { PATHS } from "@notesnook/desktop"; import { PATHS } from "@notesnook/desktop";
@@ -56,7 +56,7 @@ export const BackupExportSettings: SettingsGroup[] = [
key: "restore-backup", key: "restore-backup",
title: "Restore backup", title: "Restore backup",
description: "Restore a backup file from your disk drive.", description: "Restore a backup file from your disk drive.",
isHidden: () => !useUserStore.getState().isLoggedIn && !isTesting(), isHidden: () => !useUserStore.getState().isLoggedIn && !IS_TESTING,
components: [ components: [
{ {
type: "button", type: "button",
@@ -71,8 +71,8 @@ export const BackupExportSettings: SettingsGroup[] = [
}, },
{ {
key: "auto-backup", key: "auto-backup",
title: isDesktop() ? "Automatic backups" : "Backup reminders", title: IS_DESKTOP_APP ? "Automatic backups" : "Backup reminders",
description: isDesktop() description: IS_DESKTOP_APP
? "Backup all your data automatically at a set interval." ? "Backup all your data automatically at a set interval."
: "You will be shown regular reminders to backup your data.", : "You will be shown regular reminders to backup your data.",
isHidden: () => !isUserPremium(), isHidden: () => !isUserPremium(),
@@ -119,7 +119,7 @@ export const BackupExportSettings: SettingsGroup[] = [
key: "backup-directory", key: "backup-directory",
title: "Backups directory", title: "Backups directory",
description: "Select directory to store all backup files.", description: "Select directory to store all backup files.",
isHidden: () => !isDesktop(), isHidden: () => !IS_DESKTOP_APP,
components: [ components: [
{ {
type: "button", type: "button",

View File

@@ -27,7 +27,7 @@ import { useStore as useSettingStore } from "../../stores/setting-store";
import { getFonts } from "@notesnook/editor"; import { getFonts } from "@notesnook/editor";
import { useSpellChecker } from "../../hooks/use-spell-checker"; import { useSpellChecker } from "../../hooks/use-spell-checker";
import { SpellCheckerLanguages } from "./components/spell-checker-languages"; import { SpellCheckerLanguages } from "./components/spell-checker-languages";
import { isDesktop } from "../../utils/platform";
import { CustomizeToolbar } from "./components/customize-toolbar"; import { CustomizeToolbar } from "./components/customize-toolbar";
export const EditorSettings: SettingsGroup[] = [ export const EditorSettings: SettingsGroup[] = [
@@ -118,7 +118,7 @@ symbols (e.g. 202305261253)`,
key: "spell-check", key: "spell-check",
section: "editor", section: "editor",
header: "Spell check", header: "Spell check",
isHidden: () => !isDesktop(), isHidden: () => !IS_DESKTOP_APP,
onRender: () => { onRender: () => {
useSpellChecker.getState().refresh(); useSpellChecker.getState().refresh();
}, },

View File

@@ -51,7 +51,7 @@ import { SyncSettings } from "./sync-settings";
import { BehaviourSettings } from "./behaviour-settings"; import { BehaviourSettings } from "./behaviour-settings";
import { DesktopIntegrationSettings } from "./desktop-integration-settings"; import { DesktopIntegrationSettings } from "./desktop-integration-settings";
import { NotificationsSettings } from "./notifications-settings"; import { NotificationsSettings } from "./notifications-settings";
import { isDesktop } from "../../utils/platform";
import { BackupExportSettings } from "./backup-export-settings"; import { BackupExportSettings } from "./backup-export-settings";
import { ImporterSettings } from "./importer-settings"; import { ImporterSettings } from "./importer-settings";
import { VaultSettings } from "./vault-settings"; import { VaultSettings } from "./vault-settings";
@@ -105,7 +105,7 @@ const sectionGroups: SectionGroup[] = [
key: "desktop", key: "desktop",
title: "Desktop integration", title: "Desktop integration",
icon: Desktop, icon: Desktop,
isHidden: () => !isDesktop() isHidden: () => !IS_DESKTOP_APP
}, },
{ key: "notifications", title: "Notifications", icon: Notification } { key: "notifications", title: "Notifications", icon: Notification }
] ]

View File

@@ -81,7 +81,7 @@ What data is collected & when?`,
"Prevent Notesnook app from being captured by any screen capturing software like TeamViewer & AnyDesk.", "Prevent Notesnook app from being captured by any screen capturing software like TeamViewer & AnyDesk.",
onStateChange: (listener) => onStateChange: (listener) =>
useSettingStore.subscribe((s) => s.privacyMode, listener), useSettingStore.subscribe((s) => s.privacyMode, listener),
isHidden: () => !isDesktop() || getPlatform() === "linux", isHidden: () => !IS_DESKTOP_APP || getPlatform() === "linux",
components: [ components: [
{ {
type: "toggle", type: "toggle",

View File

@@ -16,11 +16,20 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* eslint-disable no-var */
import "vite/client"; import "vite/client";
import "vite-plugin-svgr/client"; import "vite-plugin-svgr/client";
declare global { declare global {
var PUBLIC_URL: string;
var APP_VERSION: string;
var GIT_HASH: string;
var IS_DESKTOP_APP: boolean;
var IS_TESTING: boolean;
var PLATFORM: "web" | "desktop";
var IS_BETA: boolean;
interface Window { interface Window {
os?: () => NodeJS.Platform | "mas"; os?: () => NodeJS.Platform | "mas";
NativeNNCrypto?: new () => import("@notesnook/crypto").NNCrypto; NativeNNCrypto?: new () => import("@notesnook/crypto").NNCrypto;

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { isDesktop } from "../utils/platform";
import { checkForUpdate } from "../utils/updater"; import { checkForUpdate } from "../utils/updater";
import { AppEventManager, AppEvents } from "../common/app-events"; import { AppEventManager, AppEvents } from "../common/app-events";
@@ -57,7 +57,7 @@ export function useAutoUpdater() {
} }
function updateNotAvailable() { function updateNotAvailable() {
if (isDesktop()) changeStatus({ type: "updated" }); if (IS_DESKTOP_APP) changeStatus({ type: "updated" });
else changeStatus(); else changeStatus();
} }

View File

@@ -23,9 +23,9 @@ import "allotment/dist/style.css";
import "../utils/analytics"; import "../utils/analytics";
import "../app.css"; import "../app.css";
if (import.meta.env.NODE_ENV === "production") { // if (import.meta.env.PROD) {
console.log = () => {}; // console.log = () => {};
} // }
const memory = { const memory = {
isDatabaseLoaded: false isDatabaseLoaded: false
@@ -45,4 +45,4 @@ export async function loadDatabase(persistence: "db" | "memory" = "db") {
await initializeDatabase(persistence); await initializeDatabase(persistence);
memory.isDatabaseLoaded = true; memory.isDatabaseLoaded = true;
} }

View File

@@ -22,7 +22,6 @@ import {
useStore as useUserStore, useStore as useUserStore,
store as userstore store as userstore
} from "../stores/user-store"; } from "../stores/user-store";
import { isTesting } from "../utils/platform";
export function useIsUserPremium() { export function useIsUserPremium() {
const user = useUserStore((store) => store.user); const user = useUserStore((store) => store.user);
@@ -30,7 +29,7 @@ export function useIsUserPremium() {
} }
export function isUserPremium(user?: User) { export function isUserPremium(user?: User) {
if (isTesting()) return true; if (IS_TESTING) return true;
if (!user) user = userstore.get().user; if (!user) user = userstore.get().user;
const subStatus = user?.subscription?.type; const subStatus = user?.subscription?.type;

View File

@@ -23,7 +23,7 @@ import { AppEventManager, AppEvents } from "./common/app-events";
import { render } from "react-dom"; import { render } from "react-dom";
import { getCurrentHash, getCurrentPath, makeURL } from "./navigation"; import { getCurrentHash, getCurrentPath, makeURL } from "./navigation";
import Config from "./utils/config"; import Config from "./utils/config";
import { isTesting } from "./utils/platform";
import { initalizeLogger, logger } from "./utils/logger"; import { initalizeLogger, logger } from "./utils/logger";
import { AuthProps } from "./views/auth"; import { AuthProps } from "./views/auth";
import { loadDatabase } from "./hooks/use-database"; import { loadDatabase } from "./hooks/use-database";
@@ -125,7 +125,7 @@ function fallbackRoute(): RouteWithPath {
} }
function redirectToRegistration(path: Routes): RouteWithPath<AuthProps> | null { function redirectToRegistration(path: Routes): RouteWithPath<AuthProps> | null {
if (!isTesting() && !shouldSkipInitiation() && !routes[path]) { if (!IS_TESTING && !shouldSkipInitiation() && !routes[path]) {
window.history.replaceState({}, "", makeURL("/signup", getCurrentHash())); window.history.replaceState({}, "", makeURL("/signup", getCurrentHash()));
return { route: routes["/signup"], path: "/signup" }; return { route: routes["/signup"], path: "/signup" };
} }
@@ -156,8 +156,7 @@ async function renderApp() {
} = getRoute(); } = getRoute();
if (serviceWorkerWhitelist.includes(path)) await initializeServiceWorker(); if (serviceWorkerWhitelist.includes(path)) await initializeServiceWorker();
if (import.meta.env.REACT_APP_PLATFORM === "desktop") if (IS_DESKTOP_APP) await loadDatabase("db");
await loadDatabase("db");
logger.measure("app render"); logger.measure("app render");
@@ -174,7 +173,7 @@ async function renderApp() {
} }
async function initializeServiceWorker() { async function initializeServiceWorker() {
if (import.meta.env.REACT_APP_PLATFORM !== "desktop") { if (!IS_DESKTOP_APP) {
logger.info("Initializing service worker..."); logger.info("Initializing service worker...");
const serviceWorker = await import("./service-worker-registration"); const serviceWorker = await import("./service-worker-registration");

View File

@@ -19,11 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { INNCrypto } from "@notesnook/crypto/dist/src/interfaces"; import { INNCrypto } from "@notesnook/crypto/dist/src/interfaces";
import CryptoWorker from "@notesnook/crypto-worker/dist/src/worker.js?worker"; import CryptoWorker from "@notesnook/crypto-worker/dist/src/worker.js?worker";
import { isDesktop } from "../utils/platform";
async function loadNNCrypto() { async function loadNNCrypto() {
const hasWorker = "Worker" in window || "Worker" in global; const hasWorker = "Worker" in window || "Worker" in global;
if (isDesktop() && window.NativeNNCrypto) { if (IS_DESKTOP_APP && window.NativeNNCrypto) {
return window.NativeNNCrypto; return window.NativeNNCrypto;
} else if (hasWorker) { } else if (hasWorker) {
const { NNCryptoWorker } = await import("@notesnook/crypto-worker"); const { NNCryptoWorker } = await import("@notesnook/crypto-worker");

View File

@@ -29,6 +29,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// To learn more about the benefits of this model and instructions on how to // To learn more about the benefits of this model and instructions on how to
// opt-in, read https://cra.link/PWA // opt-in, read https://cra.link/PWA
type ServiceWorkerRegistrationConfig = {
onUpdate?: (registration: ServiceWorkerRegistration) => void;
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onError?: (error: Error) => void;
};
const isLocalhost = Boolean( const isLocalhost = Boolean(
window.location.hostname === "localhost" || window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address. // [::1] is the IPv6 localhost address.
@@ -39,13 +45,10 @@ const isLocalhost = Boolean(
) )
); );
export function register(config) { export function register(config: ServiceWorkerRegistrationConfig) {
if ( if (import.meta.env.PROD && "serviceWorker" in navigator) {
import.meta.env.NODE_ENV === "production" &&
"serviceWorker" in navigator
) {
// The URL constructor is available in all browsers that support SW. // The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(import.meta.env.PUBLIC_URL, window.location.href); const publicUrl = new URL(PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) { if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin // Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to // from what our page is served on. This might happen if a CDN is used to
@@ -54,7 +57,7 @@ export function register(config) {
} }
window.addEventListener("load", () => { window.addEventListener("load", () => {
const swUrl = `${import.meta.env.PUBLIC_URL}/service-worker.js`; const swUrl = `${PUBLIC_URL}/service-worker.js`;
if (isLocalhost) { if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not. // This is running on localhost. Let's check if a service worker still exists or not.
@@ -76,7 +79,10 @@ export function register(config) {
} }
} }
function registerValidSW(swUrl, config) { function registerValidSW(
swUrl: string,
config: ServiceWorkerRegistrationConfig
) {
navigator.serviceWorker navigator.serviceWorker
.register(swUrl) .register(swUrl)
.then((registration) => { .then((registration) => {
@@ -120,7 +126,10 @@ function registerValidSW(swUrl, config) {
}); });
} }
function checkValidServiceWorker(swUrl, config) { function checkValidServiceWorker(
swUrl: string,
config: ServiceWorkerRegistrationConfig
) {
// Check if the service worker can be found. If it can't reload the page. // Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, { fetch(swUrl, {
headers: { "Service-Worker": "script" } headers: { "Service-Worker": "script" }

View File

@@ -16,14 +16,8 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* eslint-disable no-var */
/* eslint-disable no-restricted-globals */ /// <reference lib="webworker" />
// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
// for the list of available Workbox modules, or add any other
// code you'd like.
// You can also remove this file if you'd prefer not to use a
// service worker, and the Workbox build step will be skipped.
import { clientsClaim } from "workbox-core"; import { clientsClaim } from "workbox-core";
import { ExpirationPlugin } from "workbox-expiration"; import { ExpirationPlugin } from "workbox-expiration";
@@ -31,20 +25,17 @@ import { precacheAndRoute, createHandlerBoundToURL } from "workbox-precaching";
import { registerRoute } from "workbox-routing"; import { registerRoute } from "workbox-routing";
import { StaleWhileRevalidate } from "workbox-strategies"; import { StaleWhileRevalidate } from "workbox-strategies";
declare var self: ServiceWorkerGlobalScope & typeof globalThis;
clientsClaim(); clientsClaim();
// Precache all of the assets generated by your build process. const precacheRoutes = self.__WB_MANIFEST;
// Their URLs are injected into the manifest variable below.
// This variable must be present somewhere in your service worker file,
// even if you decide not to use precaching. See https://cra.link/PWA
/**
* @type {import("workbox-precaching/_types").PrecacheEntry[]}
*/
var precacheRoutes = self.__WB_MANIFEST;
const filters = [/KaTeX/i, /hack/i, /code-lang-/i]; const filters = [/KaTeX/i, /hack/i, /code-lang-/i];
precacheAndRoute( precacheAndRoute(
precacheRoutes.filter((route) => { precacheRoutes.filter((route) => {
return filters.every((filter) => !filter.test(route.url)); return filters.every(
(filter) => !filter.test(typeof route === "string" ? route : route.url)
);
}) })
); );
@@ -70,7 +61,7 @@ registerRoute(
return true; return true;
}, },
createHandlerBoundToURL(import.meta.env.PUBLIC_URL + "/index.html") createHandlerBoundToURL(PUBLIC_URL + "/index.html")
); );
// An example runtime caching route for requests that aren't handled by the // An example runtime caching route for requests that aren't handled by the
@@ -101,12 +92,11 @@ self.addEventListener("message", (event) => {
break; break;
case "GET_VERSION": case "GET_VERSION":
{ {
const VERSION = import.meta.env.REACT_APP_VERSION; if (!event.source) return;
const HASH = import.meta.env.REACT_APP_GIT_HASH;
event.source.postMessage({ event.source.postMessage({
type: data.type, type: data.type,
version: VERSION, version: APP_VERSION,
hash: HASH hash: GIT_HASH
}); });
} }
break; break;

View File

@@ -25,7 +25,6 @@ import { isUserPremium } from "../hooks/use-is-user-premium";
import { SUBSCRIPTION_STATUS } from "../common/constants"; import { SUBSCRIPTION_STATUS } from "../common/constants";
import { appVersion } from "../utils/version"; import { appVersion } from "../utils/version";
import { findItemAndDelete } from "@notesnook/core/utils/array"; import { findItemAndDelete } from "@notesnook/core/utils/array";
import { isTesting } from "../utils/platform";
/** /**
* @extends {BaseStore<AnnouncementStore>} * @extends {BaseStore<AnnouncementStore>}
@@ -35,7 +34,7 @@ class AnnouncementStore extends BaseStore {
dialogAnnouncements = []; dialogAnnouncements = [];
refresh = async () => { refresh = async () => {
if (isTesting()) return; if (IS_TESTING) return;
try { try {
const inlineAnnouncements = []; const inlineAnnouncements = [];
@@ -77,7 +76,7 @@ export { useStore, store };
export const allowedPlatforms = [ export const allowedPlatforms = [
"all", "all",
import.meta.env.REACT_APP_PLATFORM, PLATFORM,
...(window.os ? [window.os()] : []) ...(window.os ? [window.os()] : [])
]; ];

View File

@@ -26,7 +26,7 @@ import { showReminderPreviewDialog } from "../common/dialog-controller";
import dayjs from "dayjs"; import dayjs from "dayjs";
import Config from "../utils/config"; import Config from "../utils/config";
import { store as notestore } from "./note-store"; import { store as notestore } from "./note-store";
import { isDesktop, isTesting } from "../utils/platform";
import { desktop } from "../common/desktop-bridge"; import { desktop } from "../common/desktop-bridge";
/** /**
@@ -57,7 +57,7 @@ async function resetReminders(reminders) {
await TaskScheduler.stopAllWithPrefix("reminder:"); await TaskScheduler.stopAllWithPrefix("reminder:");
if ( if (
!isTesting() && !IS_TESTING &&
(!("Notification" in window) || Notification.permission !== "granted") (!("Notification" in window) || Notification.permission !== "granted")
) )
return; return;
@@ -93,12 +93,12 @@ function scheduleReminder(id, reminder, cron) {
return TaskScheduler.register(`reminder:${id}`, cron, async () => { return TaskScheduler.register(`reminder:${id}`, cron, async () => {
if (!Config.get("reminderNotifications", true)) return; if (!Config.get("reminderNotifications", true)) return;
if (isTesting()) { if (IS_TESTING) {
window.confirm("Reminder activated!"); window.confirm("Reminder activated!");
return; return;
} }
if (isDesktop()) { if (IS_DESKTOP_APP) {
const tag = await desktop?.integration.showNotification.query({ const tag = await desktop?.integration.showNotification.query({
title: reminder.title, title: reminder.title,
body: reminder.description, body: reminder.description,

View File

@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import CompressorWorker from "./compressor.worker.ts?worker"; import CompressorWorker from "./compressor.worker.ts?worker";
import type { Compressor as CompressorWorkerType } from "./compressor.worker"; import type { Compressor as CompressorWorkerType } from "./compressor.worker";
import { wrap, Remote } from "comlink"; import { wrap, Remote } from "comlink";
import { isDesktop } from "./platform";
import { desktop } from "../common/desktop-bridge"; import { desktop } from "../common/desktop-bridge";
export class Compressor { export class Compressor {
@@ -28,21 +28,21 @@ export class Compressor {
private compressor!: Remote<CompressorWorkerType>; private compressor!: Remote<CompressorWorkerType>;
constructor() { constructor() {
if (!isDesktop()) { if (!IS_DESKTOP_APP) {
this.worker = new CompressorWorker(); this.worker = new CompressorWorker();
this.compressor = wrap<CompressorWorkerType>(this.worker); this.compressor = wrap<CompressorWorkerType>(this.worker);
} }
} }
async compress(data: string) { async compress(data: string) {
if (isDesktop()) if (IS_DESKTOP_APP)
return await desktop?.compress.gzip.query({ data, level: 6 }); return await desktop?.compress.gzip.query({ data, level: 6 });
return await this.compressor.gzip({ data, level: 6 }); return await this.compressor.gzip({ data, level: 6 });
} }
async decompress(data: string) { async decompress(data: string) {
if (isDesktop()) return await desktop?.compress.gunzip.query(data); if (IS_DESKTOP_APP) return await desktop?.compress.gunzip.query(data);
return await this.compressor.gunzip({ data }); return await this.compressor.gunzip({ data });
} }

View File

@@ -122,10 +122,6 @@ export function getDownloadLink(platform: string) {
} }
} }
export function isDesktop() {
return "os" in window || import.meta.env.REACT_APP_PLATFORM === "desktop";
}
export function isMac() { export function isMac() {
return ( return (
getPlatform() === "macOS" || getPlatform() === "darwin" || isMacStoreApp() getPlatform() === "macOS" || getPlatform() === "darwin" || isMacStoreApp()
@@ -135,7 +131,3 @@ export function isMac() {
export function isMacStoreApp() { export function isMacStoreApp() {
return window.os && window.os() === "mas"; return window.os && window.os() === "mas";
} }
export function isTesting() {
return !!import.meta.env.REACT_APP_TEST;
}

View File

@@ -21,7 +21,7 @@ import Config from "./config";
export function isTelemetryEnabled() { export function isTelemetryEnabled() {
// telemetry is always disabled in DEBUG/TEST mode // telemetry is always disabled in DEBUG/TEST mode
if (import.meta.env.NODE_ENV !== "production") return false; if (import.meta.env.DEV) return false;
return Config.get("telemetry", false); return Config.get("telemetry", false);
} }

View File

@@ -19,11 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { AppEventManager, AppEvents } from "../common/app-events"; import { AppEventManager, AppEvents } from "../common/app-events";
import { desktop } from "../common/desktop-bridge"; import { desktop } from "../common/desktop-bridge";
import { isDesktop } from "./platform";
import { appVersion, getServiceWorkerVersion } from "./version"; import { appVersion, getServiceWorkerVersion } from "./version";
export async function checkForUpdate() { export async function checkForUpdate() {
if (isDesktop()) await desktop?.updater.check.query(); if (IS_DESKTOP_APP) await desktop?.updater.check.query();
else { else {
AppEventManager.publish(AppEvents.checkingForUpdate); AppEventManager.publish(AppEvents.checkingForUpdate);
@@ -35,7 +34,11 @@ export async function checkForUpdate() {
const workerVersion = await getServiceWorkerVersion( const workerVersion = await getServiceWorkerVersion(
registration.waiting registration.waiting
); );
if (!workerVersion || workerVersion.numerical <= appVersion.numerical) { if (
!workerVersion ||
workerVersion.numerical <= appVersion.numerical ||
workerVersion.hash === appVersion.hash
) {
registration.waiting.postMessage({ type: "SKIP_WAITING" }); registration.waiting.postMessage({ type: "SKIP_WAITING" });
continue; continue;
} }
@@ -52,17 +55,21 @@ export async function checkForUpdate() {
} }
export async function downloadUpdate() { export async function downloadUpdate() {
if (isDesktop()) await desktop?.updater.download.query(); if (IS_DESKTOP_APP) await desktop?.updater.download.query();
else { else {
console.log("Force updating"); console.log("Force updating");
if (!("serviceWorker" in navigator)) return; try {
const registration = await navigator.serviceWorker.ready; if (!("serviceWorker" in navigator)) return;
await registration.update(); const registration = await navigator.serviceWorker.ready;
await registration.update();
} catch (e) {
console.error(e);
}
} }
} }
export async function installUpdate() { export async function installUpdate() {
if (isDesktop()) await desktop?.updater.install.query(); if (IS_DESKTOP_APP) await desktop?.updater.install.query();
else { else {
const registrations = const registrations =
(await navigator.serviceWorker?.getRegistrations()) || []; (await navigator.serviceWorker?.getRegistrations()) || [];

View File

@@ -20,15 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
export type Platforms = "web" | "desktop"; export type Platforms = "web" | "desktop";
export type AppVersion = typeof appVersion; export type AppVersion = typeof appVersion;
export const appVersion = { export const appVersion = {
formatted: format( formatted: format(APP_VERSION, GIT_HASH, PLATFORM, IS_BETA),
import.meta.env.REACT_APP_VERSION, clean: formatVersion(APP_VERSION),
import.meta.env.REACT_APP_GIT_HASH, numerical: parseInt(APP_VERSION || "0"),
import.meta.env.REACT_APP_PLATFORM as Platforms, hash: GIT_HASH,
import.meta.env.REACT_APP_BETA === "true" isBeta: IS_BETA
),
clean: formatVersion(import.meta.env.REACT_APP_VERSION),
numerical: parseInt(import.meta.env.REACT_APP_VERSION || "0"),
isBeta: import.meta.env.REACT_APP_BETA === "true"
}; };
function format( function format(
@@ -59,11 +55,12 @@ export function getServiceWorkerVersion(
if (type !== "GET_VERSION") return; if (type !== "GET_VERSION") return;
clearTimeout(timeout); clearTimeout(timeout);
const { version } = ev.data; const { version, hash } = ev.data;
resolve({ resolve({
formatted: formatVersion(version), formatted: formatVersion(version),
numerical: parseInt(version), numerical: parseInt(version),
clean: formatVersion(version), clean: formatVersion(version),
hash,
isBeta: appVersion.isBeta isBeta: appVersion.isBeta
}); });
}); });

View File

@@ -38,7 +38,7 @@ import useDatabase from "../hooks/use-database";
import Loader from "../components/loader"; import Loader from "../components/loader";
import { showToast } from "../utils/toast"; import { showToast } from "../utils/toast";
import AuthContainer from "../components/auth-container"; import AuthContainer from "../components/auth-container";
import { isTesting } from "../utils/platform";
import { useTimer } from "../hooks/use-timer"; import { useTimer } from "../hooks/use-timer";
import { AuthenticatorType } from "../dialogs/mfa/types"; import { AuthenticatorType } from "../dialogs/mfa/types";
import { import {
@@ -521,7 +521,7 @@ function AccountRecovery(props: BaseAuthComponentProps<"recover">) {
const url = await db.user?.recoverAccount(form.email.toLowerCase()); const url = await db.user?.recoverAccount(form.email.toLowerCase());
console.log(url); console.log(url);
if (isTesting()) { if (IS_TESTING) {
window.open(url, "_self"); window.open(url, "_self");
return; return;
} }

View File

@@ -21,128 +21,23 @@ import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react-swc";
import svgrPlugin from "vite-plugin-svgr"; import svgrPlugin from "vite-plugin-svgr";
import envCompatible from "vite-plugin-env-compatible"; import envCompatible from "vite-plugin-env-compatible";
import { VitePWA, ManifestOptions } from "vite-plugin-pwa"; import { VitePWA } from "vite-plugin-pwa";
import autoprefixer from "autoprefixer"; import autoprefixer from "autoprefixer";
import { WEB_MANIFEST } from "./web-manifest";
import { execSync } from "child_process";
import { version } from "./package.json";
const WEB_MANIFEST: Partial<ManifestOptions> = { const gitHash = (() => {
name: "Notesnook", try {
description: return execSync("git rev-parse --short HEAD").toString().trim();
"A fully open source & end-to-end encrypted note taking alternative to Evernote.", } catch (e) {
short_name: "Notesnook", return process.env.GIT_HASH || "gitless";
shortcuts: [ }
{ })();
name: "New note", const appVersion = version.replaceAll(".", "");
url: "/#/notes/create",
description: "Create a new note",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
}
]
},
{
name: "New notebook",
url: "/#/notebooks/create",
description: "Create a new notebook",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
}
]
}
],
icons: [
{
src: "favicon-16x16.png",
sizes: "16x16",
type: "image/png"
},
{
src: "favicon-32x32.png",
sizes: "32x32",
type: "image/png"
},
{
src: "favicon-72x72.png",
sizes: "72x72",
type: "image/png"
},
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png"
}
],
screenshots: [
{
src: "/screenshots/screenshot-1.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-2.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-3.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-4.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-5.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-6.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-7.jpg",
sizes: "1080x1920",
type: "image/jpeg"
}
],
related_applications: [
{
platform: "play",
url: "https://play.google.com/store/apps/details?id=com.streetwriters.notesnook",
id: "com.streetwriters.notesnook"
},
{
platform: "itunes",
url: "https://apps.apple.com/us/app/notesnook-private-notes-app/id1544027013"
}
],
prefer_related_applications: true,
orientation: "any",
start_url: ".",
theme_color: "#01c352",
background_color: "#ffffff",
display: "standalone",
categories: ["productivity", "lifestyle", "education", "books"]
};
const isTesting = const isTesting =
process.env.REACT_APP_TEST === "true" || process.env.TEST === "true" || process.env.NODE_ENV === "development";
process.env.NODE_ENV === "development"; const isDesktop = process.env.PLATFORM === "desktop";
const isDesktop = process.env.REACT_APP_PLATFORM === "desktop";
export default defineConfig({ export default defineConfig({
envPrefix: "REACT_APP_", envPrefix: "REACT_APP_",
@@ -152,14 +47,23 @@ export default defineConfig({
minify: "esbuild", minify: "esbuild",
cssMinify: true, cssMinify: true,
emptyOutDir: true, emptyOutDir: true,
sourcemap: process.env.GENERATE_SOURCEMAP === "true", sourcemap: isTesting,
rollupOptions: { rollupOptions: {
output: { output: {
assetFileNames: "assets/[name]-[hash:12][extname]", assetFileNames: "assets/[name]-[hash:12][extname]",
chunkFileNames: "[name]-[hash:12].js" chunkFileNames: "assets/[name]-[hash:12].js"
} }
} }
}, },
define: {
GIT_HASH: `"${gitHash}"`,
APP_VERSION: `"${appVersion}"`,
PUBLIC_URL: `"${process.env.PUBLIC_URL || ""}"`,
IS_DESKTOP_APP: isDesktop,
PLATFORM: `"${process.env.PLATFORM}"`,
IS_TESTING: process.env.TEST === "true",
IS_BETA: process.env.BETA === "true"
},
logLevel: process.env.NODE_ENV === "production" ? "warn" : "info", logLevel: process.env.NODE_ENV === "production" ? "warn" : "info",
resolve: { resolve: {
dedupe: ["react", "react-dom", "@mdi/js", "@mdi/react", "@emotion/react"], dedupe: ["react", "react-dom", "@mdi/js", "@mdi/react", "@emotion/react"],
@@ -194,7 +98,7 @@ export default defineConfig({
manifest: WEB_MANIFEST, manifest: WEB_MANIFEST,
injectRegister: null, injectRegister: null,
srcDir: "src", srcDir: "src",
filename: "service-worker.js" filename: "service-worker.ts"
}) })
]), ]),
react({ react({

135
apps/web/web-manifest.ts Normal file
View File

@@ -0,0 +1,135 @@
/*
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 { ManifestOptions } from "vite-plugin-pwa";
export const WEB_MANIFEST: Partial<ManifestOptions> = {
name: "Notesnook",
description:
"A fully open source & end-to-end encrypted note taking alternative to Evernote.",
short_name: "Notesnook",
shortcuts: [
{
name: "New note",
url: "/#/notes/create",
description: "Create a new note",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
}
]
},
{
name: "New notebook",
url: "/#/notebooks/create",
description: "Create a new notebook",
icons: [
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
}
]
}
],
icons: [
{
src: "favicon-16x16.png",
sizes: "16x16",
type: "image/png"
},
{
src: "favicon-32x32.png",
sizes: "32x32",
type: "image/png"
},
{
src: "favicon-72x72.png",
sizes: "72x72",
type: "image/png"
},
{
src: "/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png"
},
{
src: "/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png"
}
],
screenshots: [
{
src: "/screenshots/screenshot-1.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-2.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-3.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-4.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-5.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-6.jpg",
sizes: "1080x1920",
type: "image/jpeg"
},
{
src: "/screenshots/screenshot-7.jpg",
sizes: "1080x1920",
type: "image/jpeg"
}
],
related_applications: [
{
platform: "play",
url: "https://play.google.com/store/apps/details?id=com.streetwriters.notesnook",
id: "com.streetwriters.notesnook"
},
{
platform: "itunes",
url: "https://apps.apple.com/us/app/notesnook-private-notes-app/id1544027013"
}
],
prefer_related_applications: true,
orientation: "any",
start_url: ".",
theme_color: "#01c352",
background_color: "#ffffff",
display: "standalone",
categories: ["productivity", "lifestyle", "education", "books"]
};