mirror of https://github.com/fantasticit/think.git
client: use next-pwa, fix import different version yjs
This commit is contained in:
parent
2ee25bcb50
commit
d823775e3e
|
@ -39,6 +39,7 @@
|
||||||
"node": ">=16.5.0"
|
"node": ">=16.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^17.0.35",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"lint-staged": "^12.4.1",
|
"lint-staged": "^12.4.1",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const semi = require('@douyinfe/semi-next').default({});
|
const semi = require('@douyinfe/semi-next').default({});
|
||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
const withOffline = require('next-offline');
|
const withPWA = require('next-pwa');
|
||||||
const { getConfig } = require('@think/config');
|
const { getConfig } = require('@think/config');
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
|
|
||||||
|
@ -27,26 +27,11 @@ const nextConfig = semi({
|
||||||
compiler: {
|
compiler: {
|
||||||
removeConsole: true,
|
removeConsole: true,
|
||||||
},
|
},
|
||||||
workboxOpts: {
|
pwa: {
|
||||||
runtimeCaching: [
|
disable: process.env.NODE_ENV !== 'production',
|
||||||
{
|
dest: '.next',
|
||||||
urlPattern: /.(png|jpg|jpeg|svg|webp)$/,
|
sw: 'service-worker.js',
|
||||||
handler: 'CacheFirst',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
urlPattern: /api/,
|
|
||||||
handler: 'NetworkFirst',
|
|
||||||
options: {
|
|
||||||
cacheableResponse: {
|
|
||||||
statuses: [0, 200],
|
|
||||||
headers: {
|
|
||||||
'x-sw': 'true',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = withOffline(nextConfig);
|
module.exports = withPWA(nextConfig);
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
"markdown-it-sub": "^1.0.0",
|
"markdown-it-sub": "^1.0.0",
|
||||||
"markdown-it-sup": "^1.0.0",
|
"markdown-it-sup": "^1.0.0",
|
||||||
"next": "12.0.10",
|
"next": "12.0.10",
|
||||||
"next-offline": "^5.0.5",
|
"next-pwa": "^5.5.2",
|
||||||
"prosemirror-markdown": "^1.7.0",
|
"prosemirror-markdown": "^1.7.0",
|
||||||
"prosemirror-model": "^1.16.1",
|
"prosemirror-model": "^1.16.1",
|
||||||
"prosemirror-schema-list": "^1.1.6",
|
"prosemirror-schema-list": "^1.1.6",
|
||||||
|
@ -93,8 +93,6 @@
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"toggle-selection": "^1.0.6",
|
"toggle-selection": "^1.0.6",
|
||||||
"viewerjs": "^1.10.4",
|
"viewerjs": "^1.10.4",
|
||||||
"y-indexeddb": "^9.0.7",
|
|
||||||
"y-prosemirror": "^1.0.14",
|
|
||||||
"yjs": "^13.5.24"
|
"yjs": "^13.5.24"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -102,6 +100,7 @@
|
||||||
"@types/react": "17.0.38",
|
"@types/react": "17.0.38",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||||
"@typescript-eslint/parser": "^5.21.0",
|
"@typescript-eslint/parser": "^5.21.0",
|
||||||
|
"copy-webpack-plugin": "11.0.0",
|
||||||
"eslint": "^8.14.0",
|
"eslint": "^8.14.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
@ -109,7 +108,9 @@
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.5.0",
|
"eslint-plugin-react-hooks": "^4.5.0",
|
||||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "4.5.5"
|
"typescript": "4.5.5",
|
||||||
|
"workbox-webpack-plugin": "^6.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,13 @@
|
||||||
import * as math from 'lib0/math';
|
import * as math from 'lib0/math';
|
||||||
import { Plugin } from 'prosemirror-state'; // eslint-disable-line
|
import { Plugin } from 'prosemirror-state'; // eslint-disable-line
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view'; // eslint-disable-line
|
import { Decoration, DecorationSet } from 'prosemirror-view'; // eslint-disable-line
|
||||||
import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from 'y-prosemirror';
|
import {
|
||||||
import { yCursorPluginKey, ySyncPluginKey } from 'y-prosemirror';
|
absolutePositionToRelativePosition,
|
||||||
|
relativePositionToAbsolutePosition,
|
||||||
|
setMeta,
|
||||||
|
yCursorPluginKey,
|
||||||
|
ySyncPluginKey,
|
||||||
|
} from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Extension } from '@tiptap/core';
|
import { Extension } from '@tiptap/core';
|
||||||
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from 'y-prosemirror';
|
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||||
import { UndoManager } from 'yjs';
|
import { UndoManager } from 'yjs';
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Transaction } from 'prosemirror-state';
|
import { Transaction } from 'prosemirror-state';
|
||||||
import { ySyncPluginKey } from 'y-prosemirror';
|
import { ySyncPluginKey } from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||||
|
|
||||||
export function isChangeOrigin(transaction: Transaction): boolean {
|
export function isChangeOrigin(transaction: Transaction): boolean {
|
||||||
return !!transaction.getMeta(ySyncPluginKey);
|
return !!transaction.getMeta(ySyncPluginKey);
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
import * as idb from 'lib0/indexeddb.js';
|
||||||
|
import * as mutex from 'lib0/mutex.js';
|
||||||
|
import { Observable } from 'lib0/observable.js';
|
||||||
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
|
const customStoreName = 'custom';
|
||||||
|
const updatesStoreName = 'updates';
|
||||||
|
|
||||||
|
export const PREFERRED_TRIM_SIZE = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {IndexeddbPersistence} idbPersistence
|
||||||
|
*/
|
||||||
|
export const fetchUpdates = (idbPersistence) => {
|
||||||
|
const [updatesStore] = idb.transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]); // , 'readonly')
|
||||||
|
return idb
|
||||||
|
.getAll(updatesStore, idb.createIDBKeyRangeLowerBound(idbPersistence._dbref, false))
|
||||||
|
.then((updates) =>
|
||||||
|
idbPersistence._mux(() =>
|
||||||
|
Y.transact(
|
||||||
|
idbPersistence.doc,
|
||||||
|
() => {
|
||||||
|
updates.forEach((val) => Y.applyUpdate(idbPersistence.doc, val));
|
||||||
|
},
|
||||||
|
idbPersistence,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(() =>
|
||||||
|
idb.getLastKey(updatesStore).then((lastKey) => {
|
||||||
|
idbPersistence._dbref = lastKey + 1;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() =>
|
||||||
|
idb.count(updatesStore).then((cnt) => {
|
||||||
|
idbPersistence._dbsize = cnt;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => updatesStore);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {IndexeddbPersistence} idbPersistence
|
||||||
|
* @param {boolean} forceStore
|
||||||
|
*/
|
||||||
|
export const storeState = (idbPersistence, forceStore = true) =>
|
||||||
|
fetchUpdates(idbPersistence).then((updatesStore) => {
|
||||||
|
if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
|
||||||
|
idb
|
||||||
|
.addAutoKey(updatesStore, Y.encodeStateAsUpdate(idbPersistence.doc))
|
||||||
|
.then(() => idb.del(updatesStore, idb.createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
|
||||||
|
.then(() =>
|
||||||
|
idb.count(updatesStore).then((cnt) => {
|
||||||
|
idbPersistence._dbsize = cnt;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
|
export const clearDocument = (name) => idb.deleteDB(name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends Observable<string>
|
||||||
|
*/
|
||||||
|
export class IndexeddbPersistence extends Observable {
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {Y.Doc} doc
|
||||||
|
*/
|
||||||
|
constructor(name, doc) {
|
||||||
|
super();
|
||||||
|
this.doc = doc;
|
||||||
|
this.name = name;
|
||||||
|
this._mux = mutex.createMutex();
|
||||||
|
this._dbref = 0;
|
||||||
|
this._dbsize = 0;
|
||||||
|
/**
|
||||||
|
* @type {IDBDatabase|null}
|
||||||
|
*/
|
||||||
|
this.db = null;
|
||||||
|
this.synced = false;
|
||||||
|
this._db = idb.openDB(name, (db) => idb.createStores(db, [['updates', { autoIncrement: true }], ['custom']]));
|
||||||
|
/**
|
||||||
|
* @type {Promise<IndexeddbPersistence>}
|
||||||
|
*/
|
||||||
|
this.whenSynced = this._db.then((db) => {
|
||||||
|
this.db = db;
|
||||||
|
const currState = Y.encodeStateAsUpdate(doc);
|
||||||
|
return fetchUpdates(this)
|
||||||
|
.then((updatesStore) => idb.addAutoKey(updatesStore, currState))
|
||||||
|
.then(() => {
|
||||||
|
this.emit('synced', [this]);
|
||||||
|
this.synced = true;
|
||||||
|
return this;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Timeout in ms untill data is merged and persisted in idb.
|
||||||
|
*/
|
||||||
|
this._storeTimeout = 1000;
|
||||||
|
/**
|
||||||
|
* @type {any}
|
||||||
|
*/
|
||||||
|
this._storeTimeoutId = null;
|
||||||
|
/**
|
||||||
|
* @param {Uint8Array} update
|
||||||
|
*/
|
||||||
|
this._storeUpdate = (update) =>
|
||||||
|
this._mux(() => {
|
||||||
|
if (this.db) {
|
||||||
|
const [updatesStore] = idb.transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName]);
|
||||||
|
idb.addAutoKey(updatesStore, update);
|
||||||
|
if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
|
||||||
|
// debounce store call
|
||||||
|
if (this._storeTimeoutId !== null) {
|
||||||
|
clearTimeout(this._storeTimeoutId);
|
||||||
|
}
|
||||||
|
this._storeTimeoutId = setTimeout(() => {
|
||||||
|
storeState(this, false);
|
||||||
|
this._storeTimeoutId = null;
|
||||||
|
}, this._storeTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
doc.on('update', this._storeUpdate);
|
||||||
|
this.destroy = this.destroy.bind(this);
|
||||||
|
doc.on('destroy', this.destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this._storeTimeoutId) {
|
||||||
|
clearTimeout(this._storeTimeoutId);
|
||||||
|
}
|
||||||
|
this.doc.off('update', this._storeUpdate);
|
||||||
|
this.doc.off('destroy', this.destroy);
|
||||||
|
return this._db.then((db) => {
|
||||||
|
db.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys this instance and removes all data from indexeddb.
|
||||||
|
*
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
clearData() {
|
||||||
|
return this.destroy().then(() => {
|
||||||
|
idb.deleteDB(this.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String | number | ArrayBuffer | Date} key
|
||||||
|
* @return {Promise<String | number | ArrayBuffer | Date | any>}
|
||||||
|
*/
|
||||||
|
get(key) {
|
||||||
|
return this._db.then((db) => {
|
||||||
|
const [custom] = idb.transact(db, [customStoreName], 'readonly');
|
||||||
|
return idb.get(custom, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String | number | ArrayBuffer | Date} key
|
||||||
|
* @param {String | number | ArrayBuffer | Date} value
|
||||||
|
* @return {Promise<String | number | ArrayBuffer | Date>}
|
||||||
|
*/
|
||||||
|
set(key, value) {
|
||||||
|
return this._db.then((db) => {
|
||||||
|
const [custom] = idb.transact(db, [customStoreName]);
|
||||||
|
return idb.put(custom, value, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String | number | ArrayBuffer | Date} key
|
||||||
|
* @return {Promise<undefined>}
|
||||||
|
*/
|
||||||
|
del(key) {
|
||||||
|
return this._db.then((db) => {
|
||||||
|
const [custom] = idb.transact(db, [customStoreName]);
|
||||||
|
return idb.del(custom, key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue