Skip to content

Commit 2863ffe

Browse files
authored
fix(template-asset): invalidate cached _previewRoot upon receiving new _data (#8003)
1 parent bf0ece5 commit 2863ffe

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

src/framework/handlers/template.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ class TemplateHandler extends ResourceHandler {
5252
this.decoder ??= new TextDecoder('utf-8');
5353
return new Template(this._app, JSON.parse(this.decoder.decode(data)));
5454
}
55+
56+
patch(asset, registry) {
57+
// only process if this looks like valid template data
58+
if (!asset || !asset.resource || !asset.data || !asset.data.entities) {
59+
return;
60+
}
61+
62+
const template = asset.resource;
63+
64+
// the `data` setter will handle cache invalidation
65+
template.data = asset.data;
66+
}
5567
}
5668

5769
export { TemplateHandler };

src/framework/template.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ class Template {
5454

5555
this._templateRoot = parser.parse(this._data);
5656
}
57+
58+
set data(value) {
59+
this._data = value;
60+
// cache invalidation: the next instantiate() will parse and use the new _data
61+
this._templateRoot = null;
62+
}
63+
64+
get data() {
65+
return this._data;
66+
}
5767
}
5868

5969
export { Template };
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { expect } from 'chai';
2+
3+
import { Asset } from '../../../src/framework/asset/asset.js';
4+
import { createApp } from '../../app.mjs';
5+
import { jsdomSetup, jsdomTeardown } from '../../jsdom.mjs';
6+
7+
// Example template data in the database
8+
function createFakeTemplateData(name) {
9+
const rootId = 'root-guid';
10+
return {
11+
entities: {
12+
[rootId]: {
13+
name,
14+
resource_id: rootId,
15+
parent: null,
16+
children: [],
17+
position: [0, 0, 0],
18+
rotation: [0, 0, 0],
19+
scale: [1, 1, 1],
20+
components: {}
21+
}
22+
}
23+
};
24+
}
25+
26+
describe('TemplateHandler', function () {
27+
let app;
28+
29+
beforeEach(function () {
30+
jsdomSetup();
31+
app = createApp();
32+
});
33+
34+
afterEach(function () {
35+
app?.destroy();
36+
app = null;
37+
jsdomTeardown();
38+
});
39+
40+
41+
it('should reparse the new template data', function (done) {
42+
// For this test case we pretend the data is already loaded
43+
const file = null;
44+
45+
const data1 = createFakeTemplateData('root1');
46+
const data2 = createFakeTemplateData('root2');
47+
48+
const templateAsset = new Asset('Template B', 'template', file, data1);
49+
50+
app.assets.add(templateAsset);
51+
app.assets.load(templateAsset);
52+
53+
templateAsset.ready(function (asset) {
54+
const first = asset.resource.instantiate();
55+
expect(first.name).to.equal('root1');
56+
57+
// change asset data: should trigger handler.patch and resource invalidation
58+
asset.data = data2;
59+
60+
expect(asset.resource.data).to.equal(asset.data);
61+
62+
const second = asset.resource.instantiate();
63+
expect(second.name).to.equal('root2');
64+
done();
65+
});
66+
});
67+
});

0 commit comments

Comments
 (0)