Show a helpful warning if the user hadn't called studio.initialize() in a timely manner

This commit is contained in:
Aria Minaei 2022-07-06 15:53:14 +02:00 committed by Aria
parent fb02b297f1
commit 88df1ef004

View file

@ -25,6 +25,34 @@ import checkForUpdates from './checkForUpdates'
export type CoreExports = typeof _coreExports export type CoreExports = typeof _coreExports
const STUDIO_NOT_INITIALIZED_MESSAGE = `You seem to have imported '@theatre/studio' but haven't initialized it. You can initialize the studio by:
\`\`\`
import studio from '@theatre/studio'
studio.initialize()
\`\`\`
* If you didn't mean to import '@theatre/studio', this means that your bundler is not tree-shaking it. This is most likely a bundler misconfiguration.
* If you meant to import '@theatre/studio' without showing its UI, you can do that by running:
\`\`\`
import studio from '@theatre/studio'
studio.initialize()
studio.ui.hide()
\`\`\`
`
const STUDIO_INITIALIZED_LATE_MSG = `You seem to have imported '@theatre/studio' but called \`studio.initialize()\` after some delay.
Theatre.js projects remain in pending mode (won't play their sequences) until the studio is initialized, so you should place the \`studio.initialize()\` line right after the import line:
\`\`\`
import studio from '@theatre/studio'
// ... and other imports
studio.initialize()
\`\`\`
`
export class Studio { export class Studio {
readonly ui!: UI readonly ui!: UI
readonly publicApi: IStudio readonly publicApi: IStudio
@ -41,9 +69,23 @@ export class Studio {
private readonly _cache = new SimpleCache() private readonly _cache = new SimpleCache()
readonly paneManager: PaneManager readonly paneManager: PaneManager
/**
* An atom holding the exports of '\@theatre/core'. Will be undefined if '\@theatre/core' is never imported
*/
private _coreAtom = new Atom<{core?: CoreExports}>({}) private _coreAtom = new Atom<{core?: CoreExports}>({})
/**
* A Deferred that will resolve once studio is initialized (and its state is read from storage)
*/
private readonly _initializedDeferred: Deferred<void> = defer() private readonly _initializedDeferred: Deferred<void> = defer()
/**
* Tracks whether studio.initialize() is called.
*/
private _initializeFnCalled = false private _initializeFnCalled = false
/**
* Will be set to true if studio.initialize() isn't called after 100ms.
*/
private _didWarnAboutNotInitializing = false
get atomP() { get atomP() {
return this._store.atomP return this._store.atomP
@ -60,19 +102,27 @@ export class Studio {
this._attachToIncomingProjects() this._attachToIncomingProjects()
this.paneManager = new PaneManager(this) this.paneManager = new PaneManager(this)
/** setTimeout(() => {
* @remarks if (!this._initializeFnCalled) {
* TODO If studio.initialize() is not called within a few milliseconds, console.error(STUDIO_NOT_INITIALIZED_MESSAGE)
* we should console.warn() the user that `@theatre/studio` is still in this._didWarnAboutNotInitializing = true
* their bundle. This way we can avoid issues like }
* [this](https://discord.com/channels/870988717190426644/892469755225710642/892479678797971486). }, 100)
*/
} }
async initialize(opts?: Parameters<IStudio['initialize']>[0]) { async initialize(opts?: Parameters<IStudio['initialize']>[0]) {
if (this._initializeFnCalled) { if (this._initializeFnCalled) {
console.warn(
`\`studio.initialize()\` is already called. You only need to call \`studio.initialize()\` once.`,
)
return this._initializedDeferred.promise return this._initializedDeferred.promise
} }
this._initializeFnCalled = true
if (this._didWarnAboutNotInitializing) {
console.warn(STUDIO_INITIALIZED_LATE_MSG)
}
const storeOpts: Parameters<typeof this._store['initialize']>[0] = { const storeOpts: Parameters<typeof this._store['initialize']>[0] = {
persistenceKey: 'theatre-0.4', persistenceKey: 'theatre-0.4',
usePersistentStorage: true, usePersistentStorage: true,