====== TerrainNode simple scene review ====== * So last time I was working on this project, I think I was working around this "TerrainNode" scene implementation, which is available in the file **src/scenes/test7_terrainNode.ts** * This is the scene currently loaded in the main app when using `landjs_serve` since we have in **src/app/app.component.ts**: ngOnInit(): void { // retrieve the WebGL2 context: log.DEBUG("Retriving webGL2 context..."); let ctx = this.view.nativeElement.getContext('webgl2'); RenderContext.setCurrent(ctx); log.DEBUG("Assigned Render context!"); // Create a resource loader here: let loader = new ResourceLoader(this.http); // let scene = new Test2Scene(); // let scene = new Test2Scene(this.view.nativeElement); // let scene = new Test3Scene(this.view.nativeElement); // let scene = new Test4Scene(this.view.nativeElement); // let scene = new Test5Scene(this.view.nativeElement, loader); // let scene = new Test6Scene(this.view.nativeElement, loader); let scene = new Test7Scene(this.view.nativeElement, loader); } * We have a **loader** passed as argument here: this reminds me of how it works (roughtly): this loader is responsible for loading the "actual resources" in the context of the angular app (//I think 😋...//) * Most (all) of the important code is in the **src/nvland** folder. And in there we have multiple sub folders for the main sub-systems like "core", "ecs", "math", "render", etc. * Which reminds me that lately I spend a lot of time on the **Entity Component System (ECS)**, but that's not the last thing I was working on: * According to the git log messages, last thing I touched was the implementation of the **ElevationProducer** * And just before that, some implementation/tests around **webworkers**... I'm wondering what was the conclusion on that point ? 😏 * Checking the file **src/nvland/workers/Mat4Mult.worker.ts**: // // import * as log from '../core/Log'; import { sprintf } from "sprintf-js"; import { Mat4 } from "../math/Mat4"; // import { BaseObject } from "../core/BaseObject"; // class MyClass extends BaseObject // { // public constructor() { // super(); // } // }; // function multMat(n: number, a: Mat4, b: Mat4): Mat4 // { // for(let i=0;i { // self.console.log("Received data: "+JSON.stringify(event)) // let a = new Mat4(); // a.rotateX(45.0); // // Get the limit from the event data // let a = new Mat4(); // a.fromArray(event.data.mat1); // let b = new Mat4(); // b.fromArray(event.data.mat2); // let obj = new MyClass(); // log.DEBUG("Hello!"); // let msg = sprintf("Hello %s", obj.name); let msg = sprintf("Hello %s", "manu"); // let n = event.data.count; // let res = multMat(n,a,b); // Send the primes back to the main thread // postMessage({ result: res }); // postMessage({ result: a.getElements() }); postMessage({ result: [42] }); // postMessage({ result: [msg.length] }); }); * => This reminds me that I could **not** successfully "import" some of my other modules and use them in a worker **inside a unit test**, but I think this was **working** when executed inside the main app directly 🤔 (or am I dreaming ? => I should redo that test to confirm it or find where this is done.) * Arrrggg.... trying to restore some of the Mat4 computation in the worker and then call that in the main app on init: protected async init() { // Test the webworker: let promise = new Promise(function (resolve: ((val: number[]) => void), reject) { console.log("Creating Mat4Mult...") // const worker = new Worker(new URL('./Mat4Mult.worker', import.meta.url)); const worker = new Worker(new URL('src/nvland/workers/Mat4Mult.worker', import.meta.url)); // const worker = new Worker('Mat4Mult.worker.ts', {type: "module"}) worker.onmessage = (event) => { resolve(event.data.result); }; let a = Mat4.makeRotateX(43.0); let b = Mat4.makeRotateY(12.0); console.log("Mat1: " + a.toString()); console.log("Mat2: " + b.toString()); // worker.onmessage = ({ data }) => { // console.log(`page got message: ${JSON.stringify(data)}`); // }; // worker.postMessage({ mat1: a.getElements(), mat2: b.getElements(), count: 100 }); // worker.postMessage('hello'); }); let res = await promise; this.DEBUG("Received result data: " + JSON.stringify(res)); } ... But right now it seems I only get a black screen out of this 😖 not good... Arrff, no: stupid me, it's working, but I have to uncomment the **worker.postMessage()** statement of course lol. * But now in the unit tests, I get **no test executed at all**: $ landjs_test > nerv-land-js@0.0.0 test > ng test --no-watch --code-coverage \ Generating browser application bundles (phase: building)...04 02 2022 13:38:22.538:INFO [karma-server]: Karma v6.3.9 server started at http://loca lhost:9876/ 04 02 2022 13:38:22.540:INFO [launcher]: Launching browsers ChromeHeadless with concurrency unlimited 04 02 2022 13:38:22.549:INFO [launcher]: Starting browser ChromeHeadless √ Browser application bundle generation complete. 04 02 2022 13:38:34.874:INFO [Chrome Headless 97.0.4692.99 (Windows 10)]: Connected on socket fO2t8ywxepFNO-UmAAAB with id 68198556 Chrome Headless 97.0.4692.99 (Windows 10): Executed 0 of 0 SUCCESS (0.005 secs / 0 secs) TOTAL: 0 SUCCESS =============================== Coverage summary =============================== Statements : Unknown% ( 0/0 ) Branches : Unknown% ( 0/0 ) Functions : Unknown% ( 0/0 ) Lines : Unknown% ( 0/0 ) ================================================================================ ... which is surprising, because I actually renamed the file **Mat4Mult.spec.ts** to **Mat4Mult.bad.ts** before running those tests! 😳 So, what now ? * Trying to rename the "Mat4Mult.bad.ts" file to "Mat4Mult.bad.old" => **nope** still not working! 😨 So, it this due to my "Mat4Mult.worker.ts" file then ? -> Commenting some content there... [nope], then commenting even more code there... Now it's OK, running 28 tests without error. * => So it is something on how I process the files named ".worker.ts" ? Hmmm 🤔 I kind of remember I was doing something special about that, let's see if I can find it back. * Okay, so, in my angular.json file I have that section for the tests: "test": { "builder": "@angular-builders/custom-webpack:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "inlineStyleLanguage": "scss", "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "src/styles.scss" ], "customWebpackConfig": { "path": "./webpack.partial.js" }, "scripts": [], "webWorkerTsConfig": "tsconfig.worker.json" } } * So we have the **webWorkerTsConfig** pointing to a dedicated tsconfig file: { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/worker", "lib": [ "es2018", "webworker" ], "types": [] }, "include": [ "src/**/*.worker.ts" ] } ... and in there our reference to the .worker.ts files. => looking for more infos on that "webWorkerTsConfig" config entry. * Found this page: https://github.com/angular/angular-cli/issues/19372 * => Maybe I need ''%%"exclude": ["* */*.worker.ts"]%%'' in the other tsconfig files ? => nope, this doesn't seem to help 😭 * Okay, so, time for a recap: I could loose a lot of time trying to figure out how to run those unit test on webworkers, so let's cut it short for now: * I should ensure that the unit tests **do not** try to load my complex webworkers, so should use a dedicated extensions for those that can be tested: * => My testing environment will now use the **tsconfig.lightworker.ts** config and only find the **.lightworker.ts** scripts. * Updated the reference in angular.json as needed: ''"webWorkerTsConfig": "tsconfig.lightworker.json"'' * And no... **still getting an error with that**: ./src/nvland/workers/Mat4Mult.worker.ts - Error: Module build failed (from ./node_modules/@ngtools/webpack/src/ivy/index.js): Error: D:\Projects\NervLandJS\src\nvland\workers\Mat4Mult.worker.ts is missing from the TypeScript compilation. Please make sure it is in your tscon fig via the 'files' or 'include' property. at D:\Projects\NervLandJS\node_modules\@ngtools\webpack\src\ivy\loader.js:59:26 * I gonna cry... 😭😭 * Okay, so, now, considering if there could be a different way to "load" a webworker script: maybe using soem feature from webpack itself ? Investigating... * Found that page: https://dannadori.medium.com/how-to-bundle-webworker-in-npm-package-620dcec922e1 * So now trying with the **worker-loader** package: * First installing the package with npm: landjs_npm install --save worker-loader * Then no special rule to add in our webpack partial, but we need the **typings/worker-loader.d.ts** file: declare module "worker-loader!*" { class WebpackWorker extends Worker { constructor(); } export default WebpackWorker; } * Now we update our worker typescript file to use the framework: const ctx: Worker = self as any; onmessage = async (event) => { setTimeout(() => { ctx.postMessage(`[WORKER_TS] Waited ${event.data}ms`); }, event.data) } * Next we setup loading that worker in the main app: import MatWorker from "worker-loader?inline=no-fallback!src/nvland/workers/Mat4Mult.worker.ts"; // Later in the code: const worker = new MatWorker() worker.onmessage = (event:any) => { resolve(event.data.result); }; let a = Mat4.makeRotateX(43.0); let b = Mat4.makeRotateY(12.0); console.log("Mat1: " + a.toString()); console.log("Mat2: " + b.toString()); worker.postMessage({ mat1: a.getElements(), mat2: b.getElements(), count: 100 }); /*//*/ * But of course, this is not working for use and will produce a typescript error when compile the app: Error: src/scenes/test7_terrainNode.ts:21:23 - error TS2691: An import path cannot end with a '.ts' extension. Consider importing 'worker-loader?inl ine=no-fallback!src/nvland/workers/Mat4Mult.worker.js' instead. 21 import MatWorker from "worker-loader?inline=no-fallback!src/nvland/workers/Mat4Mult.worker.ts"; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** × Failed to compile. * I'm so desperate now lol... I even try loading my worker script as a JS file, and still no luck: this is such a mess... * Now trying to follow the instructions from https://v4.webpack.js.org/loaders/worker-loader/ more carefully. Nope. Pointless. * => **OKAY, so now discarding this whole worker-loader usage experiment**: I'm not getting anywhere with that unfortunately. * So, trying with comlink now: https://blog.lacolaco.net/2018/12/enjoyable-webworkers-in-angular/ 🥴 ? * hmmm 🤔... Actually, wait a minute... I'm now just realizing that in my previous experiment I actually had **2 locations** where I was trying to load my "Mat4Mult.worker.ts" file, but using on one side the worker-loader, and on the other location the webpack 5 mechanism 😐! So basically: I should try that again now before moving to the next option 🤣 * So installing worker-loader again: landjs_npm install --save worker-loader * Adding **typings/worker-loader.d.ts** file: declare module "worker-loader!*" { class WebpackWorker extends Worker { constructor(); } export default WebpackWorker; } * And updating webpack.partial.json: module.exports = { module: { rules: [ { enforce: 'pre', test: /\.worker\.ts$/, loader: "worker-loader", }, { test: /\.glsl$/, exclude: /node_modules/, loader: 'raw-loader' } ] } }; * But no: compilation is still failing without any clear error message: √ Compiled successfully. √ Browser application bundle generation complete. Initial Chunk Files | Names | Size main.js | main | 306.21 kB runtime.js | runtime | 6.75 kB 3 unchanged chunks Build at: 2022-02-04T21:27:27.836Z - Hash: 6e2c2425dc9e35b3e572 - Time: 968ms × Failed to compile. * So let's leave that path behind us, and try **comlink** as suggested above: * Reference page: https://blog.lacolaco.net/2018/12/enjoyable-webworkers-in-angular/ * Installing that package: $ landjs_npm install comlink * **Nayy...** => This might be worth using eventually, but it will not lead us anywhere here: the problem is deeper than that: when we simply have to load one worker file in the testing environment, and it has some non trivial imports... * **Finally! Found a working/acceptable solution!** * We are now defining our worker creation directly in the **main.ts** file: // And building the app we should support loading webworkers: (window as any).createWorker = function() : any { return new Worker(new URL('nvland/workers/Mat4Mult.worker', import.meta.url)) } * And that file and all its dependencies don't get loaded in the testing environment! So we finally don't have to load a .worker.ts file during testing :-) ! * Feeew... that was an hard one. => So, the solution we have here is not the cleanest, but I feel happy I have something working at least! So let's call it a day now. Tomorrow I should try to get back to the **Elevation Producer**