1
1
import SketchManager from './core/SketchManager' ;
2
2
import PaperSizes from './paper-sizes' ;
3
+ import { getClientAPI } from './util' ;
4
+ import defined from 'defined' ;
3
5
4
- const CACHE = 'canvas-sketch-file-cache' ;
6
+ const CACHE = 'hot-id-cache' ;
7
+ const runtimeCollisions = [ ] ;
5
8
6
- function cacheGet ( file ) {
7
- window [ CACHE ] = window [ CACHE ] || { } ;
8
- return window [ CACHE ] [ file ] ;
9
+ function isHotReload ( ) {
10
+ const client = getClientAPI ( ) ;
11
+ return client && client . hot ;
9
12
}
10
13
11
- function cachePut ( file , data ) {
12
- window [ CACHE ] = window [ CACHE ] || { } ;
13
- window [ CACHE ] [ file ] = data ;
14
+ function cacheGet ( id ) {
15
+ const client = getClientAPI ( ) ;
16
+ if ( ! client ) return undefined ;
17
+ client [ CACHE ] = client [ CACHE ] || { } ;
18
+ return client [ CACHE ] [ id ] ;
14
19
}
15
20
16
- function canvasSketch ( sketch , settings = { } , file ) {
21
+ function cachePut ( id , data ) {
22
+ const client = getClientAPI ( ) ;
23
+ if ( ! client ) return undefined ;
24
+ client [ CACHE ] = client [ CACHE ] || { } ;
25
+ client [ CACHE ] [ id ] = data ;
26
+ }
27
+
28
+ function getTimeProp ( oldManager , newSettings ) {
29
+ // Static sketches ignore the time persistency
30
+ return newSettings . animate ? { time : oldManager . props . time } : undefined ;
31
+ }
32
+
33
+ function canvasSketch ( sketch , settings = { } ) {
17
34
if ( settings . p5 ) {
18
35
if ( settings . canvas || ( settings . context && typeof settings . context !== 'string' ) ) {
19
36
throw new Error ( `In { p5 } mode, you can't pass your own canvas or context, unless the context is a "webgl" or "2d" string` ) ;
@@ -24,43 +41,60 @@ function canvasSketch (sketch, settings = {}, file) {
24
41
settings = Object . assign ( { } , settings , { canvas : false , context } ) ;
25
42
}
26
43
27
- const isCaching = typeof file === 'string' ;
44
+ const isHot = isHotReload ( ) ;
45
+ let hotID ;
46
+ if ( isHot ) {
47
+ hotID = defined ( settings . id , process . env . SKETCH_ENTRY ) ;
48
+ }
49
+ let isInjecting = isHot && typeof hotID === 'string' ;
50
+
51
+ if ( isInjecting && runtimeCollisions . includes ( hotID ) ) {
52
+ console . warn ( `Warning: You have multiple calls to canvasSketch() in --hot mode. You must pass unique { id } strings in settings to enable hot reload across multiple sketches. ` , hotID ) ;
53
+ isInjecting = false ;
54
+ }
28
55
29
56
let preload = Promise . resolve ( ) ;
30
57
31
- if ( isCaching ) {
32
- const previousData = cacheGet ( file ) ;
58
+ if ( isInjecting ) {
59
+ // Mark this as already spotted in this runtime instance
60
+ runtimeCollisions . push ( hotID ) ;
61
+
62
+ const previousData = cacheGet ( hotID ) ;
33
63
if ( previousData ) {
34
- preload = previousData . load . then ( manager => {
35
- const newProps = Object . assign ( { } , manager . props ) ;
36
- manager . destroy ( ) ;
37
- return {
38
- time : newProps . time
39
- } ;
40
- } ) . catch ( ( ) => {
41
- // If an error occurred during load, we will just
42
- // destroy old manager and reset props
64
+ const next = ( ) => {
65
+ // Grab new props from old sketch instance
66
+ const newProps = getTimeProp ( previousData . manager , settings ) ;
67
+ // Destroy the old instance
43
68
previousData . manager . destroy ( ) ;
44
- return null ;
45
- } ) ;
69
+ // Pass along new props
70
+ return newProps ;
71
+ } ;
72
+
73
+ // Move along the next data...
74
+ preload = previousData . load . then ( next ) . catch ( next ) ;
46
75
}
47
76
}
48
77
49
78
return preload . then ( newProps => {
50
79
const manager = new SketchManager ( ) ;
51
80
let result ;
52
81
if ( sketch ) {
82
+ // Merge with incoming data
83
+ settings = Object . assign ( { } , settings , newProps ) ;
84
+
53
85
// Apply settings and create a canvas
54
86
manager . setup ( settings ) ;
55
- if ( newProps ) manager . update ( newProps ) ;
87
+
88
+ // Mount to DOM
56
89
manager . mount ( ) ;
90
+
57
91
// load the sketch first
58
92
result = manager . loadAndRun ( sketch ) ;
59
93
} else {
60
94
result = Promise . resolve ( manager ) ;
61
95
}
62
- if ( isCaching ) {
63
- cachePut ( file , { load : result , manager } ) ;
96
+ if ( isInjecting ) {
97
+ cachePut ( hotID , { load : result , manager } ) ;
64
98
}
65
99
return result ;
66
100
} ) ;
0 commit comments