@jdultra/threedtiles 3.3.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/index.html +1 -1
- package/package.json +14 -13
- package/src/decoder/B3DMDecoder.js +63 -64
- package/src/index.js +135 -33
- package/src/tileset/OGC3DTile.js +2 -2
- package/src/tileset/TileLoader.js +0 -9
- package/src/tileset/instanced/InstancedOGC3DTile.js +45 -0
- package/src/tileset/instanced/InstancedTile.js +510 -0
- package/src/tileset/instanced/InstancedTileLoader.js +322 -0
- package/src/tileset/instanced/JsonTile.js +41 -0
- package/src/tileset/instanced/MeshTile.js +75 -0
- package/webpack.config.js +117 -107
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { LinkedHashMap } from 'js-utils-z';
|
|
2
|
+
import { B3DMDecoder } from "../../decoder/B3DMDecoder";
|
|
3
|
+
import { setIntervalAsync } from 'set-interval-async/dynamic';
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
import { MeshTile } from './MeshTile';
|
|
6
|
+
import { JsonTile } from './JsonTile';
|
|
7
|
+
|
|
8
|
+
let concurentDownloads = 0;
|
|
9
|
+
|
|
10
|
+
class InstancedTileLoader {
|
|
11
|
+
constructor(scene, meshCallback, maxCachedItems, maxInstances) {
|
|
12
|
+
this.meshCallback = meshCallback;
|
|
13
|
+
this.maxInstances = maxInstances;
|
|
14
|
+
this.cache = new LinkedHashMap();
|
|
15
|
+
this.maxCachedItems = !!maxCachedItems ? maxCachedItems : 100;
|
|
16
|
+
this.scene = scene;
|
|
17
|
+
|
|
18
|
+
this.ready = [];
|
|
19
|
+
this.downloads = [];
|
|
20
|
+
this.nextReady = [];
|
|
21
|
+
this.nextDownloads = [];
|
|
22
|
+
this.init();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
update(){
|
|
26
|
+
const self = this;
|
|
27
|
+
|
|
28
|
+
self.cache._data.forEach(v=>{
|
|
29
|
+
v.update();
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
init(){
|
|
34
|
+
|
|
35
|
+
const self = this;
|
|
36
|
+
setIntervalAsync(() => {
|
|
37
|
+
self.download();
|
|
38
|
+
}, 10);
|
|
39
|
+
setIntervalAsync(() => {
|
|
40
|
+
const start = Date.now();
|
|
41
|
+
let loaded = 0;
|
|
42
|
+
do {
|
|
43
|
+
loaded = self.loadBatch();
|
|
44
|
+
} while (loaded > 0 && (Date.now() - start) <= 0)
|
|
45
|
+
|
|
46
|
+
}, 10);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
download() {
|
|
50
|
+
const self = this;
|
|
51
|
+
if (self.nextDownloads.length == 0) {
|
|
52
|
+
self.getNextDownloads();
|
|
53
|
+
if (self.nextDownloads.length == 0) return;
|
|
54
|
+
}
|
|
55
|
+
while (self.nextDownloads.length > 0 && concurentDownloads < 500) {
|
|
56
|
+
const nextDownload = self.nextDownloads.shift();
|
|
57
|
+
if (!!nextDownload && nextDownload.shouldDoDownload()) {
|
|
58
|
+
//nextDownload.doDownload();
|
|
59
|
+
concurentDownloads++;
|
|
60
|
+
if(nextDownload.path.includes(".b3dm")){
|
|
61
|
+
fetch(nextDownload.path, {signal: nextDownload.abortController.signal}).then(result => {
|
|
62
|
+
concurentDownloads--;
|
|
63
|
+
if (!result.ok) {
|
|
64
|
+
console.error("could not load tile with path : " + path)
|
|
65
|
+
throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
66
|
+
}
|
|
67
|
+
return result.arrayBuffer();
|
|
68
|
+
|
|
69
|
+
})
|
|
70
|
+
.then(resultArrayBuffer=>{
|
|
71
|
+
return B3DMDecoder.parseB3DMInstanced(resultArrayBuffer, self.meshCallback, self.maxInstances);
|
|
72
|
+
})
|
|
73
|
+
.then(mesh=>{
|
|
74
|
+
nextDownload.tile.setObject(mesh);
|
|
75
|
+
self.ready.unshift(nextDownload);
|
|
76
|
+
|
|
77
|
+
})
|
|
78
|
+
.catch(e=>console.error(e));
|
|
79
|
+
}else if(nextDownload.path.includes(".json")){
|
|
80
|
+
concurentDownloads++;
|
|
81
|
+
fetch(nextDownload.path, {signal: nextDownload.abortController.signal}).then(result => {
|
|
82
|
+
concurentDownloads--;
|
|
83
|
+
if (!result.ok) {
|
|
84
|
+
console.error("could not load tile with path : " + path)
|
|
85
|
+
throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
86
|
+
}
|
|
87
|
+
return result.json();
|
|
88
|
+
|
|
89
|
+
}).then(json => {
|
|
90
|
+
nextDownload.tile.setObject(json, nextDownload.path);
|
|
91
|
+
self.ready.unshift(nextDownload);
|
|
92
|
+
})
|
|
93
|
+
.catch(e=>console.error(e))
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
loadBatch() {
|
|
101
|
+
if (this.nextReady.length == 0) {
|
|
102
|
+
this.getNextReady();
|
|
103
|
+
if (this.nextReady.length == 0) return 0;
|
|
104
|
+
}
|
|
105
|
+
const download = this.nextReady.shift();
|
|
106
|
+
if (!download) return 0;
|
|
107
|
+
|
|
108
|
+
if(!!download.tile.addToScene)download.tile.addToScene();
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getNextReady() {
|
|
113
|
+
let smallestLevel = Number.MAX_VALUE;
|
|
114
|
+
let smallestDistance = Number.MAX_VALUE;
|
|
115
|
+
let closest = -1;
|
|
116
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
117
|
+
|
|
118
|
+
if (!this.ready[i].distanceFunction) {// if no distance function, must be a json, give absolute priority!
|
|
119
|
+
this.nextReady.push(this.ready.splice(i, 1)[0]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (this.nextReady.length > 0) return;
|
|
123
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
124
|
+
const dist = this.ready[i].distanceFunction();
|
|
125
|
+
if (dist < smallestDistance) {
|
|
126
|
+
smallestDistance = dist;
|
|
127
|
+
smallestLevel = this.ready[i].level
|
|
128
|
+
closest = i
|
|
129
|
+
} else if (dist == smallestDistance && this.ready[i].level < smallestLevel) {
|
|
130
|
+
smallestLevel = this.ready[i].level
|
|
131
|
+
closest = i
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (closest >= 0) {
|
|
135
|
+
const closestItem = this.ready.splice(closest, 1).pop();
|
|
136
|
+
this.nextReady.push(closestItem);
|
|
137
|
+
const siblings = closestItem.getSiblings();
|
|
138
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
139
|
+
if (siblings.includes(this.ready[i].uuid)) {
|
|
140
|
+
this.nextready.push(this.ready.splice(i, 1).pop());
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get(abortController, path, uuid, instancedOGC3DTile, distanceFunction, getSiblings, level) {
|
|
147
|
+
const self = this;
|
|
148
|
+
const key = simplifyPath(path);
|
|
149
|
+
|
|
150
|
+
if (!path.includes(".b3dm") && !path.includes(".json")) {
|
|
151
|
+
console.error("the 3DTiles cache can only be used to load B3DM and json data");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const cachedTile = self.cache.get(key);
|
|
156
|
+
if (!!cachedTile) {
|
|
157
|
+
cachedTile.addInstance(instancedOGC3DTile);
|
|
158
|
+
return;
|
|
159
|
+
} else {
|
|
160
|
+
|
|
161
|
+
if (path.includes(".b3dm")) {
|
|
162
|
+
const tile = new MeshTile(self.scene);
|
|
163
|
+
tile.addInstance(instancedOGC3DTile);
|
|
164
|
+
if(self.cache.has(key)){
|
|
165
|
+
console.log("élkbhj")
|
|
166
|
+
}
|
|
167
|
+
self.cache.put(key, tile);
|
|
168
|
+
|
|
169
|
+
const realAbortController = new AbortController();
|
|
170
|
+
abortController.signal.addEventListener("abort", () => {
|
|
171
|
+
if (tile.getCount() == 0) {
|
|
172
|
+
realAbortController.abort();
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
this.downloads.push({
|
|
176
|
+
abortController: realAbortController,
|
|
177
|
+
tile: tile,
|
|
178
|
+
key: key,
|
|
179
|
+
path: path,
|
|
180
|
+
distanceFunction: distanceFunction,
|
|
181
|
+
getSiblings: getSiblings,
|
|
182
|
+
level: level,
|
|
183
|
+
uuid: uuid,
|
|
184
|
+
shouldDoDownload: () => {
|
|
185
|
+
return true;
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
}else if(path.includes(".json")){
|
|
189
|
+
const tile = new JsonTile();
|
|
190
|
+
tile.addInstance(instancedOGC3DTile);
|
|
191
|
+
self.cache.put(key, tile);
|
|
192
|
+
|
|
193
|
+
const realAbortController = new AbortController();
|
|
194
|
+
abortController.signal.addEventListener("abort", () => {
|
|
195
|
+
if (tile.getCount() == 0) {
|
|
196
|
+
realAbortController.abort();
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
this.downloads.push({
|
|
200
|
+
abortController: realAbortController,
|
|
201
|
+
tile: tile,
|
|
202
|
+
key: key,
|
|
203
|
+
path: path,
|
|
204
|
+
distanceFunction: distanceFunction,
|
|
205
|
+
getSiblings: getSiblings,
|
|
206
|
+
level: level,
|
|
207
|
+
shouldDoDownload: () => {
|
|
208
|
+
return true;
|
|
209
|
+
},
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
getNextDownloads() {
|
|
219
|
+
let smallestLevel = Number.MAX_VALUE;
|
|
220
|
+
let smallestDistance = Number.MAX_VALUE;
|
|
221
|
+
let closest = -1;
|
|
222
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
223
|
+
const download = this.downloads[i];
|
|
224
|
+
if (!download.shouldDoDownload()) {
|
|
225
|
+
this.downloads.splice(i, 1);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (!download.distanceFunction) { // if no distance function, must be a json, give absolute priority!
|
|
229
|
+
this.nextDownloads.push(this.downloads.splice(i, 1)[0]);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (this.nextDownloads.length > 0) return;
|
|
233
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
234
|
+
const download = this.downloads[i];
|
|
235
|
+
const dist = download.distanceFunction();
|
|
236
|
+
if (dist < smallestDistance) {
|
|
237
|
+
smallestDistance = dist;
|
|
238
|
+
closest = i;
|
|
239
|
+
} else if (dist == smallestDistance && download.level < smallestLevel) {
|
|
240
|
+
smallestLevel = download.level;
|
|
241
|
+
closest = i
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (closest >= 0) {
|
|
245
|
+
const closestItem = this.downloads.splice(closest, 1).pop();
|
|
246
|
+
this.nextDownloads.push(closestItem);
|
|
247
|
+
const siblings = closestItem.getSiblings();
|
|
248
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
249
|
+
if (siblings.includes(this.downloads[i].uuid)) {
|
|
250
|
+
this.nextDownloads.push(this.downloads.splice(i, 1).pop());
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
checkSize() {
|
|
257
|
+
const self = this;
|
|
258
|
+
|
|
259
|
+
let i = 0;
|
|
260
|
+
|
|
261
|
+
while (self.cache.size() > self.maxCachedItems && i < self.cache.size()) {
|
|
262
|
+
i++;
|
|
263
|
+
const entry = self.cache.head();
|
|
264
|
+
if(entry.value.getCount()>0){
|
|
265
|
+
self.cache.remove(entry.key);
|
|
266
|
+
self.cache.put(entry.key, entry.value);
|
|
267
|
+
}else{
|
|
268
|
+
self.cache.remove(entry.key);
|
|
269
|
+
if(entry.value.instancedMesh){
|
|
270
|
+
entry.value.instancedMesh.traverse((o) => {
|
|
271
|
+
if (o.material) {
|
|
272
|
+
// dispose materials
|
|
273
|
+
if (o.material.length) {
|
|
274
|
+
for (let i = 0; i < o.material.length; ++i) {
|
|
275
|
+
o.material[i].dispose();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
o.material.dispose()
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (o.geometry) {
|
|
283
|
+
// dispose geometry
|
|
284
|
+
o.geometry.dispose();
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function simplifyPath(main_path) {
|
|
295
|
+
|
|
296
|
+
var parts = main_path.split('/'),
|
|
297
|
+
new_path = [],
|
|
298
|
+
length = 0;
|
|
299
|
+
for (var i = 0; i < parts.length; i++) {
|
|
300
|
+
var part = parts[i];
|
|
301
|
+
if (part === '.' || part === '' || part === '..') {
|
|
302
|
+
if (part === '..' && length > 0) {
|
|
303
|
+
length--;
|
|
304
|
+
}
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
new_path[length++] = part;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (length === 0) {
|
|
311
|
+
return '/';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
var result = '';
|
|
315
|
+
for (var i = 0; i < length; i++) {
|
|
316
|
+
result += '/' + new_path[i];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export { InstancedTileLoader };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
class JsonTile{
|
|
4
|
+
constructor(){
|
|
5
|
+
const self = this;
|
|
6
|
+
self.count = 0;
|
|
7
|
+
self.json;
|
|
8
|
+
self.instancedTiles = [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
addInstance(instanceTile){
|
|
12
|
+
this.instancedTiles.push(instanceTile);
|
|
13
|
+
if(this.json){
|
|
14
|
+
instanceTile.loadJson(this.json, this.url)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
setObject(json, url){
|
|
21
|
+
const self = this;
|
|
22
|
+
self.json = json;
|
|
23
|
+
self.url = url;
|
|
24
|
+
for(let i = 0; i<self.instancedTiles.length; i++){
|
|
25
|
+
self.instancedTiles[i].loadJson( self.json, self.url );
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getCount(){
|
|
30
|
+
return this.instancedTiles.length;
|
|
31
|
+
}
|
|
32
|
+
update(){
|
|
33
|
+
const self = this;
|
|
34
|
+
for(let i = self.instancedTiles.length-1; i>=0; i--){
|
|
35
|
+
if(self.instancedTiles[i].deleted){
|
|
36
|
+
self.instancedTiles.splice(i,1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}export { JsonTile };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { InstancedMesh } from 'three';
|
|
3
|
+
|
|
4
|
+
class MeshTile{
|
|
5
|
+
constructor(scene){
|
|
6
|
+
const self = this;
|
|
7
|
+
self.scene = scene;
|
|
8
|
+
self.instancedTiles = [];
|
|
9
|
+
self.instancedMesh;
|
|
10
|
+
|
|
11
|
+
self.reuseableMatrix = new THREE.Matrix4();
|
|
12
|
+
}
|
|
13
|
+
addInstance(instancedTile){
|
|
14
|
+
const self = this;
|
|
15
|
+
instancedTile.added = true;
|
|
16
|
+
instancedTile.listOMesh = self.instancedTiles;
|
|
17
|
+
self.instancedTiles.push(instancedTile);
|
|
18
|
+
if(self.instancedMesh){
|
|
19
|
+
instancedTile.loadMesh(self.instancedMesh)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addToScene(){
|
|
24
|
+
//this.instancedMesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );
|
|
25
|
+
const self = this;
|
|
26
|
+
self.instancedMesh.setMatrixAt(0,new THREE.Matrix4());
|
|
27
|
+
self.instancedMesh.instanceMatrix.needsUpdate = true;
|
|
28
|
+
self.instancedMesh.count = 1;
|
|
29
|
+
|
|
30
|
+
self.scene.add(self.instancedMesh);
|
|
31
|
+
self.instancedMesh.onAfterRender = () => {
|
|
32
|
+
delete self.instancedMesh.onAfterRender;
|
|
33
|
+
self.instancedMesh.displayedOnce = true;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setObject(instancedMesh){
|
|
38
|
+
const self = this;
|
|
39
|
+
self.instancedMesh = instancedMesh;
|
|
40
|
+
|
|
41
|
+
for(let i = 0; i<self.instancedTiles.length; i++){
|
|
42
|
+
self.instancedTiles[i].loadMesh(self.instancedMesh)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
update(){
|
|
47
|
+
const self = this;
|
|
48
|
+
|
|
49
|
+
for(let i = self.instancedTiles.length-1; i>=0; i--){
|
|
50
|
+
if(self.instancedTiles[i].deleted){
|
|
51
|
+
self.instancedTiles.splice(i,1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if(!!self.instancedMesh){
|
|
56
|
+
|
|
57
|
+
self.instancedMesh.count = 0;
|
|
58
|
+
|
|
59
|
+
for(let i = 0; i<self.instancedTiles.length; i++){
|
|
60
|
+
self.instancedTiles[i].meshContent = self.instancedMesh;
|
|
61
|
+
if(self.instancedTiles[i].materialVisibility && !!self.instancedTiles[i].meshContent){
|
|
62
|
+
self.instancedMesh.count++;
|
|
63
|
+
self.instancedMesh.setMatrixAt(self.instancedMesh.count-1, self.reuseableMatrix.multiplyMatrices(self.instancedMesh.baseMatrix, self.instancedTiles[i].getWorldMatrix()) )
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
self.instancedMesh.instanceMatrix.needsUpdate = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getCount(){
|
|
72
|
+
return this.instancedTiles.length;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}export { MeshTile };
|
package/webpack.config.js
CHANGED
|
@@ -3,124 +3,134 @@ const webpack = require("webpack");
|
|
|
3
3
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
4
4
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
|
5
5
|
const TerserPlugin = require('terser-webpack-plugin');
|
|
6
|
+
const CopyPlugin = require('copy-webpack-plugin');
|
|
6
7
|
|
|
7
8
|
const sourceDir = path.resolve(__dirname);
|
|
8
9
|
const DEFAULT_WEBPACK_PORT = 3001;
|
|
9
10
|
|
|
10
11
|
module.exports = {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
mode: "development",
|
|
13
|
+
entry: './src/index.js',
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
output: {
|
|
16
|
+
filename: "index.js",
|
|
17
|
+
path: path.resolve(__dirname, 'dist'),
|
|
18
|
+
},
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
plugins: [
|
|
21
|
+
new webpack.ProgressPlugin(),
|
|
22
|
+
new HtmlWebpackPlugin({
|
|
23
|
+
template: "index.html",
|
|
24
|
+
filename: "index.html",
|
|
25
|
+
}),
|
|
26
|
+
new MiniCssExtractPlugin({
|
|
27
|
+
filename: "[name].bundle.[hash].css"
|
|
28
|
+
}),
|
|
29
|
+
new CopyPlugin({
|
|
30
|
+
patterns: [
|
|
31
|
+
{ from: "meshes", to: "meshes" }
|
|
32
|
+
],
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
devtool: "source-map",
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
test: /\.s[ac]ss$/,
|
|
50
|
-
use: [
|
|
51
|
-
// inserts <link/> tag to generated CSS file, inside the generated index.html
|
|
52
|
-
{loader: MiniCssExtractPlugin.loader},
|
|
53
|
-
"css-loader",
|
|
54
|
-
"resolve-url-loader",
|
|
55
|
-
// Compiles Sass to CSS
|
|
56
|
-
{
|
|
57
|
-
loader: "sass-loader",
|
|
58
|
-
options: {
|
|
59
|
-
sourceMap: true // resolve-url-loader needs sourcemaps, regardless of devtool (cf. resolve-url-loader's README)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
]
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
test: /\.css$/i,
|
|
66
|
-
use: [
|
|
67
|
-
{loader: MiniCssExtractPlugin.loader},
|
|
68
|
-
"style-loader",
|
|
69
|
-
"css-loader",
|
|
38
|
+
module: {
|
|
39
|
+
rules: [
|
|
40
|
+
{
|
|
41
|
+
test: /.(js)$/,
|
|
42
|
+
include: [sourceDir],
|
|
43
|
+
loader: "babel-loader",
|
|
44
|
+
options: {
|
|
45
|
+
cacheDirectory: true,
|
|
46
|
+
presets: [
|
|
47
|
+
["@babel/preset-env", {
|
|
48
|
+
"useBuiltIns": "entry",
|
|
49
|
+
"corejs": 3
|
|
50
|
+
}]
|
|
70
51
|
]
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
test: /\.s[ac]ss$/,
|
|
56
|
+
use: [
|
|
57
|
+
// inserts <link/> tag to generated CSS file, inside the generated index.html
|
|
58
|
+
{ loader: MiniCssExtractPlugin.loader },
|
|
59
|
+
"css-loader",
|
|
60
|
+
"resolve-url-loader",
|
|
61
|
+
// Compiles Sass to CSS
|
|
62
|
+
{
|
|
63
|
+
loader: "sass-loader",
|
|
80
64
|
options: {
|
|
81
|
-
|
|
65
|
+
sourceMap: true // resolve-url-loader needs sourcemaps, regardless of devtool (cf. resolve-url-loader's README)
|
|
82
66
|
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
test: /\.css$/i,
|
|
72
|
+
use: [
|
|
73
|
+
{ loader: MiniCssExtractPlugin.loader },
|
|
74
|
+
"style-loader",
|
|
75
|
+
"css-loader",
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
test: /\.html$/i,
|
|
80
|
+
loader: "html-loader"
|
|
81
|
+
},
|
|
82
|
+
{ // loader for fonts
|
|
83
|
+
test: /\.(eot|woff|woff2|otf|ttf|svg)$/,
|
|
84
|
+
use: [{
|
|
85
|
+
loader: "file-loader",
|
|
86
|
+
options: {
|
|
87
|
+
name: "fonts/[name].[ext]"
|
|
88
|
+
}
|
|
89
|
+
}]
|
|
90
|
+
},
|
|
91
|
+
{ // loader for shaders
|
|
92
|
+
test: /\.glsl$/,
|
|
93
|
+
loader: 'webpack-glsl-loader'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
|
97
|
+
type: 'asset/resource',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
optimization: {
|
|
102
|
+
minimizer: [new TerserPlugin({
|
|
103
|
+
parallel: true,
|
|
104
|
+
terserOptions: {
|
|
105
|
+
ecma: undefined,
|
|
106
|
+
parse: {},
|
|
107
|
+
compress: {},
|
|
108
|
+
mangle: true, // Note `mangle.properties` is `false` by default.
|
|
109
|
+
module: false,
|
|
110
|
+
// Deprecated
|
|
111
|
+
output: null,
|
|
112
|
+
format: null,
|
|
113
|
+
toplevel: false,
|
|
114
|
+
nameCache: null,
|
|
115
|
+
ie8: false,
|
|
116
|
+
keep_classnames: undefined,
|
|
117
|
+
keep_fnames: false,
|
|
118
|
+
safari10: false,
|
|
119
|
+
},
|
|
120
|
+
exclude: []
|
|
121
|
+
})]
|
|
122
|
+
},
|
|
123
|
+
devServer: {
|
|
124
|
+
hot: true,
|
|
125
|
+
open: true,
|
|
126
|
+
port: DEFAULT_WEBPACK_PORT
|
|
127
|
+
},
|
|
128
|
+
resolve: {
|
|
129
|
+
extensions: [".js", ".jsx", ".json", ".ts", ".tsx"],// other stuff
|
|
130
|
+
fallback: {
|
|
131
|
+
"fs": false,
|
|
132
|
+
"path": require.resolve("path-browserify")
|
|
124
133
|
}
|
|
125
|
-
|
|
134
|
+
}
|
|
135
|
+
|
|
126
136
|
};
|