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
.then(() => {
render(<ImageTypeExample />, document.getElementById('root')) 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,7 +196,8 @@ export default class Project {
} }
this._studio = studio this._studio = studio
studio.initialized.then(async () => { studio.initialized
.then(async () => {
await initialiseProjectState(studio, this, this.config.state) await initialiseProjectState(studio, this, this.config.state)
this._pointerProxies.historic.setPointer( this._pointerProxies.historic.setPointer(
@ -210,7 +211,7 @@ export default class Project {
) )
// 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
@ -219,6 +220,10 @@ export default class Project {
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,11 +277,15 @@ 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 (reconfigure) {
} else {
if ( if (
extension === prevExtension || extension === prevExtension ||
shallowEqual(extension, prevExtension) shallowEqual(extension, prevExtension)
@ -288,7 +294,10 @@ export class Studio {
// as long as it's the same extension, we can safely ignore. // as long as it's the same extension, we can safely ignore.
return return
} }
throw new Error(`Extension id "${extension.id}" is already defined`) 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})})`,
)
}
} }
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,10 +326,17 @@ export class Studio {
const existing = allPaneClasses[classDefinition.class] const existing = allPaneClasses[classDefinition.class]
if (existing) { if (existing) {
if (reconfigure && existing.extensionId === extension.id) {
// 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( throw new Error(
`Pane class "${classDefinition.class}" already exists and is supplied by extension ${existing}`, `Pane class "${classDefinition.class}" already exists and is supplied by extension ${existing}`,
) )
} }
}
allPaneClasses[classDefinition.class] = { allPaneClasses[classDefinition.class] = {
extensionId: extension.id, extensionId: extension.id,

View file

@ -24,9 +24,14 @@ export default class UI {
} }
this._rendered = true this._rendered = true
this._nonSSRBits.then((b) => { this._nonSSRBits
.then((b) => {
b.render() 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
.then((nonSSRBits) => {
if (shouldUnmount) return // unmount requested before the toolset is mounted, so, abort if (shouldUnmount) return // unmount requested before the toolset is mounted, so, abort
unmount = nonSSRBits.renderToolset(toolsetId, htmlNode) unmount = nonSSRBits.renderToolset(toolsetId, htmlNode)
}) })
.catch((err) => {
console.error(err)
})
return () => { return () => {
if (unmount) { if (unmount) {