For our workflow, we code scripts locally in TypeScript, bundle them with Webpack and upload them to our projects. We’re looking into using the new ESM approach which requires exporting scripts within .mjs files so the parser can detect them.
We’ve run into a problem where exporting scripts indirectly causes the parser to not detect them properly. Example:
import { Script } from 'playcanvas';
/*
* Example 1: Crude immitation of how Webpack organizes and exports modules.
* The script is not detected by the parser.
*/
const modules = {
example1: () => class Example1 extends Script { }
};
const example1 = modules.example1();
export { example1 };
/*
* Example 2: Class exported via a variable.
* The script is not detected by the parser.
*/
class Example2 extends Script { }
const example2 = Example2;
export { example2 };
/*
* Example 3: Regular approach.
* The parser correctly identifies the script.
*/
class Example3 extends Script { }
export { Example3 };
Examples 1 and 2 are not detected whereas example 3 is detected just fine. Unfortunately, because Webpack bundles similarly to example 1, the parser currently can’t detect any of our scripts. Is this by design, or is this a bug? If it’s the latter, I’ll throw a ticket on GitHub.
It looks like webpack is bundling your code into a module registry. The ESM parser doesn’t support this kind of indirect module definition. It’s expecting vanilla ES Modules.
I’ve not tried it as I can’t find any online repl for Webpack, but you might get a compatible format by setting output.module = true on the Webpack config. See the docs here.
For comparison, in Rollup you can get a compatible export by setting output.format = 'es'. If you check this example you can see the ES output is correct, toggle to UMD etc and it will be incorrect. Docs are here
After unsuccessfully messing around with Webpack for a while I resorted to trying out Rollup since it looks pretty great in your example & the docs. It churns out proper bundles without much hassle and is faster too which is pretty awesome.
Thanks for the recommendation, we’ll just stick with Rollup going forward. This one’s solved.
We are using a similar workflow as you, using webpack to transcribe our scripts from TS to JS and uploading it into our projects. I’m just wondering what advantages you expect to get from exporting your scripts as .mjs files, and whether that is something that we should look into as well
Hey! It’s mostly because we want to gradually move away from ScriptType which is deprecated in engine V2. The new Script-class that replaces ScriptType can only be used with .mjs files because the parser detects Scripts via ES exports.
The reason we want to move to engine V2 is so we’ll have some peace of mind knowing we’ll get feature updates going forward (I think engine V1 is going into LTS at some point). We’re also very curious to try out the new rendering effects to add some flair to our games.
Also, cool to hear there are more devs taking this approach!
Thanks for the explanation, that sounds like something that we should look into as well I wasn’t aware that the pc.ScriptType is deprecated, we haven’t tried out the engine V2 yet.
That’s great to hear actually. We were wondering how long we could keep using ScriptType on engine V2 before really needing to switch over to Script. Adopting Script will take quite a bit of time (switching over to JSDoc and such), so that really puts our minds at ease
For anyone else switching to Rollup who wants their bundles uploaded to PlayCanvas automatically, I’ve published a small plugin on npm: rollup-plugin-playcanvas-uploader - npm.