Fix the dangling promises

This commit is contained in:
Aria Minaei 2023-08-03 10:46:36 +02:00
parent 27f918f53c
commit 041627f7e4
19 changed files with 112 additions and 67 deletions

View file

@ -66,6 +66,7 @@ module.exports = {
}, },
], ],
'@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
}, },
}, },
{ {

View file

@ -106,6 +106,6 @@ async function test1() {
iterateOnSequence() iterateOnSequence()
} }
test1().then(() => { void test1().then(() => {
console.log('test1 done') console.log('test1 done')
}) })

View file

@ -35,14 +35,14 @@ function createBundles(watch: boolean) {
// format: 'iife', // format: 'iife',
// }) // })
build({ void build({
...esbuildConfig, ...esbuildConfig,
entryPoints: [path.join(pathToPackage, 'src/core-and-studio.ts')], entryPoints: [path.join(pathToPackage, 'src/core-and-studio.ts')],
outfile: path.join(pathToPackage, 'dist/core-and-studio.js'), outfile: path.join(pathToPackage, 'dist/core-and-studio.js'),
format: 'iife', format: 'iife',
}) })
build({ void build({
...esbuildConfig, ...esbuildConfig,
entryPoints: [path.join(pathToPackage, 'src/core-only.ts')], entryPoints: [path.join(pathToPackage, 'src/core-only.ts')],
outfile: path.join(pathToPackage, 'dist/core-only.min.js'), outfile: path.join(pathToPackage, 'dist/core-only.min.js'),

View file

@ -17,7 +17,7 @@ function createBundles(watch: boolean) {
conditions: ['browser', 'node'], conditions: ['browser', 'node'],
} }
build({ void build({
...esbuildConfig, ...esbuildConfig,
outfile: path.join(pathToPackage, 'dist/index.js'), outfile: path.join(pathToPackage, 'dist/index.js'),
format: 'cjs', format: 'cjs',

View file

@ -53,7 +53,7 @@ const ImageTypeExample: React.FC<{}> = (props) => {
onClick={() => { onClick={() => {
if (sheet.sequence.position === 0) { if (sheet.sequence.position === 0) {
sheet.sequence.position = 0 sheet.sequence.position = 0
sheet.sequence.play() void sheet.sequence.play()
} else { } else {
sheet.sequence.position = 0 sheet.sequence.position = 0
} }
@ -64,6 +64,10 @@ const ImageTypeExample: React.FC<{}> = (props) => {
) )
} }
project.ready.then(() => { project.ready
render(<ImageTypeExample />, document.getElementById('root')) .then(() => {
}) render(<ImageTypeExample />, document.getElementById('root'))
})
.catch((err) => {
console.error(err)
})

View file

@ -7,7 +7,7 @@ import {Scene} from './Scene'
studio.initialize() studio.initialize()
// trigger warning notification // trigger warning notification
getProject('Sample project').sheet('Scene').sequence.play() void getProject('Sample project').sheet('Scene').sequence.play()
// fire an info notification // fire an info notification
notify.info( notify.info(
@ -16,7 +16,7 @@ notify.info(
'(and all others) at the start of index.tsx. You can also see examples of success and warnign notifications.', '(and all others) at the start of index.tsx. You can also see examples of success and warnign notifications.',
) )
getProject('Sample project').ready.then(() => { void getProject('Sample project').ready.then(() => {
// fire a success notification on project load // fire a success notification on project load
notify.success( notify.success(
'Project loaded!', 'Project loaded!',

View file

@ -3,7 +3,7 @@ import {render} from 'react-dom'
import React, {useState} from 'react' import React, {useState} from 'react'
import state from './state.json' import state from './state.json'
initialize({state}) void initialize({state})
function SomeComponent({id}: {id: string}) { function SomeComponent({id}: {id: string}) {
const {foo, $get, $set} = useControls( const {foo, $get, $set} = useControls(

View file

@ -76,7 +76,7 @@ function App() {
const bg = bgs[bgIndex] const bg = bgs[bgIndex]
const project = getProject('SpaceStress', {state}) const project = getProject('SpaceStress', {state})
const sheet = project.sheet('Scene') const sheet = project.sheet('Scene')
project.ready.then(() => sheet.sequence.play({iterationCount: Infinity})) void project.ready.then(() => sheet.sequence.play({iterationCount: Infinity}))
const allPropsObj = sheet.object('All Props Tester', allPropsObjectConfig) const allPropsObj = sheet.object('All Props Tester', allPropsObjectConfig)
console.log('allPropsObj', allPropsObj) console.log('allPropsObj', allPropsObj)

View file

@ -39,13 +39,13 @@ const elements = new Array(TOTAL_ELEMENTS).fill(0).map((_, idx) => {
return {el, sheet, obj} return {el, sheet, obj}
}) })
project.ready.then(() => { void project.ready.then(() => {
// select the playback controls obj so it shows as a tweakable control // select the playback controls obj so it shows as a tweakable control
studio.setSelection([playbackControlObj]) studio.setSelection([playbackControlObj])
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
const sheet = elements[i].sheet const sheet = elements[i].sheet
sheet.sequence.position = i * TOTAL_ELEMENTS_R * 5 sheet.sequence.position = i * TOTAL_ELEMENTS_R * 5
sheet.sequence.play({ void sheet.sequence.play({
iterationCount: Infinity, iterationCount: Infinity,
}) })
} }

View file

@ -8,11 +8,10 @@ const definedGlobals = {
'process.env.NODE_ENV': JSON.stringify('production'), 'process.env.NODE_ENV': JSON.stringify('production'),
} }
createBundles() void createBundles()
async function createBundles() { async function createBundles() {
createMainBundle() await Promise.all([createMainBundle(), createExtensionBundle()])
createExtensionBundle()
async function createMainBundle() { async function createMainBundle() {
const pathToEntry = path.join(__dirname, '../src/index.ts') const pathToEntry = path.join(__dirname, '../src/index.ts')

View file

@ -24,7 +24,7 @@ const definedGlobals = {
global: 'window', global: 'window',
} }
function createBundles(watch: boolean) { async function createBundles(watch: boolean) {
const pathToPackage = path.join(__dirname, '../') const pathToPackage = path.join(__dirname, '../')
const esbuildConfig: Parameters<typeof build>[0] = { const esbuildConfig: Parameters<typeof build>[0] = {
entryPoints: [path.join(pathToPackage, 'src/index.ts')], entryPoints: [path.join(pathToPackage, 'src/index.ts')],
@ -39,7 +39,7 @@ function createBundles(watch: boolean) {
plugins: [externalPlugin([/^[\@a-zA-Z]+/])], plugins: [externalPlugin([/^[\@a-zA-Z]+/])],
} }
build({ await build({
...esbuildConfig, ...esbuildConfig,
outfile: path.join(pathToPackage, 'dist/index.js'), outfile: path.join(pathToPackage, 'dist/index.js'),
format: 'cjs', format: 'cjs',
@ -52,4 +52,4 @@ function createBundles(watch: boolean) {
// }) // })
} }
createBundles(false) void createBundles(false)

View file

@ -24,7 +24,7 @@ const definedGlobals = {
global: 'window', global: 'window',
} }
function createBundles(watch: boolean) { async function createBundles(watch: boolean) {
const pathToPackage = path.join(__dirname, '../') const pathToPackage = path.join(__dirname, '../')
const pkgJson = require(path.join(pathToPackage, 'package.json')) const pkgJson = require(path.join(pathToPackage, 'package.json'))
const listOfDependencies = Object.keys(pkgJson.dependencies || {}) const listOfDependencies = Object.keys(pkgJson.dependencies || {})
@ -52,7 +52,7 @@ function createBundles(watch: boolean) {
], ],
} }
build({ await build({
...esbuildConfig, ...esbuildConfig,
outfile: path.join(pathToPackage, 'dist/index.js'), outfile: path.join(pathToPackage, 'dist/index.js'),
format: 'cjs', format: 'cjs',
@ -65,4 +65,4 @@ function createBundles(watch: boolean) {
// }) // })
} }
createBundles(false) void createBundles(false)

View file

@ -196,29 +196,34 @@ export default class Project {
} }
this._studio = studio this._studio = studio
studio.initialized.then(async () => { studio.initialized
await initialiseProjectState(studio, this, this.config.state) .then(async () => {
await initialiseProjectState(studio, this, this.config.state)
this._pointerProxies.historic.setPointer( this._pointerProxies.historic.setPointer(
studio.atomP.historic.coreByProject[this.address.projectId], studio.atomP.historic.coreByProject[this.address.projectId],
) )
this._pointerProxies.ahistoric.setPointer( this._pointerProxies.ahistoric.setPointer(
studio.atomP.ahistoric.coreByProject[this.address.projectId], studio.atomP.ahistoric.coreByProject[this.address.projectId],
) )
this._pointerProxies.ephemeral.setPointer( this._pointerProxies.ephemeral.setPointer(
studio.atomP.ephemeral.coreByProject[this.address.projectId], studio.atomP.ephemeral.coreByProject[this.address.projectId],
) )
// asset storage has to be initialized after the pointers are set // asset storage has to be initialized after the pointers are set
studio await studio
.createAssetStorage(this, this.config.assets?.baseUrl) .createAssetStorage(this, this.config.assets?.baseUrl)
.then((assetStorage) => { .then((assetStorage) => {
this.assetStorage = assetStorage this.assetStorage = assetStorage
this._assetStorageReadyDeferred.resolve(undefined) this._assetStorageReadyDeferred.resolve(undefined)
}) })
this._studioReadyDeferred.resolve(undefined) this._studioReadyDeferred.resolve(undefined)
}) })
.catch((err) => {
console.error(err)
throw err
})
} }
get isAttachedToStudio() { get isAttachedToStudio() {

View file

@ -354,7 +354,9 @@ async function resolveAudioBuffer(args: IAttachAudioArgs): Promise<{
} }
return new Promise<AudioContext>((resolve) => { return new Promise<AudioContext>((resolve) => {
const listener = () => { const listener = () => {
ctx.resume() ctx.resume().catch((err) => {
console.error(err)
})
} }
const eventsToHookInto: Array<keyof WindowEventMap> = [ const eventsToHookInto: Array<keyof WindowEventMap> = [
@ -412,6 +414,7 @@ async function resolveAudioBuffer(args: IAttachAudioArgs): Promise<{
const audioContext = await audioContextPromise const audioContext = await audioContextPromise
// eslint-disable-next-line @typescript-eslint/no-floating-promises
audioContext.decodeAudioData( audioContext.decodeAudioData(
arrayBuffer, arrayBuffer,
decodedBufferDeferred.resolve, decodedBufferDeferred.resolve,

View file

@ -1,3 +1,3 @@
import {createBundles} from './createBundles' import {createBundles} from './createBundles'
createBundles(false) void createBundles(false)

View file

@ -1,3 +1,3 @@
import {createBundles} from './createBundles' import {createBundles} from './createBundles'
createBundles(true) void createBundles(true)

View file

@ -28,7 +28,7 @@ const defaultProps = {
let lastProjectN = 0 let lastProjectN = 0
const studio = getStudio()! const studio = getStudio()!
studio.initialize({usePersistentStorage: false}) void studio.initialize({usePersistentStorage: false})
export async function setupTestSheet(sheetState: SheetState_Historic) { export async function setupTestSheet(sheetState: SheetState_Historic) {
const projectState: ProjectState_Historic = { const projectState: ProjectState_Historic = {

View file

@ -203,7 +203,9 @@ export class Studio {
if (process.env.NODE_ENV !== 'test') { if (process.env.NODE_ENV !== 'test') {
this.ui.render() this.ui.render()
checkForUpdates() checkForUpdates().catch((err) => {
console.error(err)
})
} }
} }
@ -266,7 +268,7 @@ export class Studio {
return this._coreAtom.pointer.core return this._coreAtom.pointer.core
} }
extend(extension: IExtension) { extend(extension: IExtension, opts?: {__experimental_reconfigure?: boolean}) {
if (!extension || typeof extension !== 'object') { if (!extension || typeof extension !== 'object') {
throw new Error(`Extensions must be JS objects`) throw new Error(`Extensions must be JS objects`)
} }
@ -275,20 +277,27 @@ export class Studio {
throw new Error(`extension.id must be a string`) throw new Error(`extension.id must be a string`)
} }
const reconfigure = opts?.__experimental_reconfigure === true
const extensionId = extension.id const extensionId = extension.id
const prevExtension = const prevExtension =
this._store.getState().ephemeral.extensions.byId[extensionId] this._store.getState().ephemeral.extensions.byId[extensionId]
if (prevExtension) { if (prevExtension) {
if ( if (reconfigure) {
extension === prevExtension || } else {
shallowEqual(extension, prevExtension) if (
) { extension === prevExtension ||
// probably running studio.extend() several times because of hot reload. shallowEqual(extension, prevExtension)
// as long as it's the same extension, we can safely ignore. ) {
return // probably running studio.extend() several times because of hot reload.
// as long as it's the same extension, we can safely ignore.
return
}
throw new Error(
`Extension id "${extension.id}" is already defined. If you mean to re-configure the extension, do it like this: studio.extend(extension, {__experimental_reconfigure: true})})`,
)
} }
throw new Error(`Extension id "${extension.id}" is already defined`)
} }
this.transaction(({drafts}) => { this.transaction(({drafts}) => {
@ -296,6 +305,14 @@ export class Studio {
const allPaneClasses = drafts.ephemeral.extensions.paneClasses const allPaneClasses = drafts.ephemeral.extensions.paneClasses
if (reconfigure && prevExtension) {
// remove all pane classes that were set by the previous version of the extension
prevExtension.panes?.forEach((classDefinition) => {
delete allPaneClasses[classDefinition.class]
})
}
// if the extension defines pane classes, add them to the list of all pane classes
extension.panes?.forEach((classDefinition) => { extension.panes?.forEach((classDefinition) => {
if (typeof classDefinition.class !== 'string') { if (typeof classDefinition.class !== 'string') {
throw new Error(`pane.class must be a string`) throw new Error(`pane.class must be a string`)
@ -309,9 +326,16 @@ export class Studio {
const existing = allPaneClasses[classDefinition.class] const existing = allPaneClasses[classDefinition.class]
if (existing) { if (existing) {
throw new Error( if (reconfigure && existing.extensionId === extension.id) {
`Pane class "${classDefinition.class}" already exists and is supplied by extension ${existing}`, // well this should never happen because we already deleted the pane class above
) console.warn(
`Pane class "${classDefinition.class}" already exists. This is a bug in Theatre.js. Please report it at https://github.com/theatre-js/theatre/issues/new`,
)
} else {
throw new Error(
`Pane class "${classDefinition.class}" already exists and is supplied by extension ${existing}`,
)
}
} }
allPaneClasses[classDefinition.class] = { allPaneClasses[classDefinition.class] = {

View file

@ -24,9 +24,14 @@ export default class UI {
} }
this._rendered = true this._rendered = true
this._nonSSRBits.then((b) => { this._nonSSRBits
b.render() .then((b) => {
}) b.render()
})
.catch((err) => {
console.error(err)
throw err
})
} }
hide() { hide() {
@ -53,10 +58,14 @@ export default class UI {
let unmount: null | (() => void) = null let unmount: null | (() => void) = null
this._nonSSRBits.then((nonSSRBits) => { this._nonSSRBits
if (shouldUnmount) return // unmount requested before the toolset is mounted, so, abort .then((nonSSRBits) => {
unmount = nonSSRBits.renderToolset(toolsetId, htmlNode) if (shouldUnmount) return // unmount requested before the toolset is mounted, so, abort
}) unmount = nonSSRBits.renderToolset(toolsetId, htmlNode)
})
.catch((err) => {
console.error(err)
})
return () => { return () => {
if (unmount) { if (unmount) {