BabylonJS / Babylon.js

Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework.
http://www.babylonjs.com
Apache License 2.0
23.24k stars 3.43k forks source link

BabylonJS Typescript imports fail for MochaJS specs #10507

Closed franz-josef-kaiser closed 3 years ago

franz-josef-kaiser commented 3 years ago

While attempting to set up a unit testing environment that involves MochaJS and BabylonJS, the importing of BabylonJS parts threw two types of errors:

  1. SyntaxError: Named export 'Camera' not found.
  2. SyntaxError: Cannot use import statement outside a module. Tests are running with a dedicated tsconfig.json and a .mocharc.js config. This GitHub repo contains a full test and demo setup.

Comparison was made to Typestrong/ts-node-repros example repo.

Key facts:

  1. Node Version: 14.17.0
  2. Mocha: loader: 'ts-node/esm'
  3. package.json: "type": "module"
  4. TS config:
    {
    "compilerOptions": {
        "module": "ES2020",
        "target": "ES2020",
        "moduleResolution": "node",
        "esModuleInterop": true
    }
    }

Note: All Mocha options can be found here.

Repro

Screenshots Console error log

Test case A

$ npm run test-A

> demo/ts-mocha-babylonjs@0.1.0 test-A
> ./node_modules/.bin/mocha --config .mocharc-A.cjs -P ./tsconfig.json

(node:133305) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time

/path/to/ts-mocha-babylonjs/tests/case-A.spec.ts:13
import { Camera } from '@babylonjs/core/Cameras/camera.js';
         ^^^^^^
SyntaxError: Named export 'Camera' not found. The requested module '@babylonjs/core/Cameras/camera.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@babylonjs/core/Cameras/camera.js';
const { Camera } = pkg;

    at ModuleJob._instantiate (internal/modules/esm/module_job.js:97:21)
    at ModuleJob.run (internal/modules/esm/module_job.js:142:20)
    at Loader.import (internal/modules/esm/loader.js:182:24)
    at formattedImport (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/esm-utils.js:7:14)
    at Object.exports.loadFilesAsync (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/esm-utils.js:55:20)
    at singleRun (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at Object.exports.handler (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/cli/run.js:362:5)

Test case B

$ npm run test-B

> demo/ts-mocha-babylonjs@0.1.0 test-B
> ./node_modules/.bin/mocha --config .mocharc-B.cjs -P ./tsconfig.json

(node:133357) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(node:133357) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

/path/to/projects/ts-mocha-babylonjs/node_modules/@babylonjs/core/Cameras/camera.js:1
import { __decorate, __extends } from "tslib";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at ModuleWrap.<anonymous> (internal/modules/esm/translators.js:195:29)
    at ModuleJob.run (internal/modules/esm/module_job.js:145:37)
    at Loader.import (internal/modules/esm/loader.js:182:24)
    at formattedImport (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/esm-utils.js:7:14)
    at Object.exports.loadFilesAsync (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/esm-utils.js:55:20)
    at singleRun (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at Object.exports.handler (/path/to/projects/ts-mocha-babylonjs/node_modules/mocha/lib/cli/run.js:362:5)
deltakosh commented 3 years ago

Hey thank you for this detailed message but as stated in the issue template,we are asking people to start discussion or questions on the forum (forum.babylonjs.com)

franz-josef-kaiser commented 3 years ago

@deltakosh I assumed with a reproduction repo, I can skip this requirement. My apologies. The issue can now be found in the forums. Can I ping you in case this issue is somehow confirmed?

deltakosh commented 3 years ago

Don't worry. We have core teams member lurking on the forum, they will answer really fast

yvele commented 2 years ago

I have exact same problem with TypeScript and Jest 🤔

Note that I'm using Node.js v14.17.6 (and npm v6.14.15)

image

Babylon.js is the only npm package I'm unable to use in my unit tests..

Any news about that? Maybe a workaround?

I've also checked the issue on the forum but I prefer GitHub issues for the notification system

Edit: I found the solution --> https://github.com/BabylonJS/Babylon.js/issues/10507#issuecomment-1004885962 👍

deltakosh commented 2 years ago

cc @RaananW

RaananW commented 2 years ago

@yvele - will you be able to share a reproduction of that issue? a project that fails?

franz-josef-kaiser commented 2 years ago

Sidenote: The source of the problem is (and will be) the imports, which can easily be checked with this npm package.

yvele commented 2 years ago

@yvele - will you be able to share a reproduction of that issue? a project that fails?

@RaananW RaananW what about https://github.com/franz-josef-kaiser/ts-mocha-bablyonjs ?

Sidenote: The source of the problem is (and will be) the imports, which can easily be checked with this npm package.

@franz-josef-kaiser I think it's not about ES5 but about CJS vs ESM.

Note that I don't have any problem bundling the code with Webpack (with Babel). I only have problems running Jest (also with Babel).

Maybe the problem is that Babylon.js is NOT flagged as ESM (so it's interpreted as CJS by default).. but uses ESM import that is not supported by CJS 🤔

sebavan commented 2 years ago

Your repo is fully working for me on win with node 12 image

yvele commented 2 years ago

Your repo is fully working for me on win with node 12 image

Hum.. but the repo provided by @franz-josef-kaiser is expecting Node 16 --> https://github.com/franz-josef-kaiser/ts-mocha-bablyonjs/blob/master/.nvmrc can you try with Node 16?

ESM went officially available starting with Node 14: https://nodejs.org/en/blog/release/v14.0.0/#ecmascript-modules-experimental-warning-removal

(I'm personally facing the issue with Node 14).

sebavan commented 2 years ago

what os are you on ?

for me it is also all good on 16 image

I wonder if it could be a path matching failing on linux for instance

franz-josef-kaiser commented 2 years ago

@yvele Please see the README notes in the package.json part scripts.

TL;DR The demo only works because I threw the instant-mocha package (config bundle) at it. Do I know why instant-mocha works? No, not at all. I tried to get behind it, but ran out of time.

image

To reproduce the real error, you have to jump back some commits. I "fixed" the demo repo to have something we can discuss internally at the company. There was no progress here or in the forums, so I saw no issue in just using the exact same repo to continue with finding some workaround and displaying it there.

yvele commented 2 years ago

@franz-josef-kaiser ok so your repro repository doesn't reproduce the error anymore 😅 (maybe you better have created a new branch for your experimentations?)

Anyway, I fixed my issue by adding a jest.config.js file to my project:

module.exports = {
  transformIgnorePatterns: [
    "/node_modules/(?!(@babylonjs\/core)/)"
  ]
};

Sometimes it happens (especially in React Native or TypeScript projects) that 3rd party modules are published as untranspiled code. Since all files inside node_modules are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors. To overcome this, you may use transformIgnorePatterns to allow transpiling such modules

See also:

franz-josef-kaiser commented 2 years ago

maybe you better have created a new branch for your experimentations?

Probably. You know, if I knew, you were waiting right around the corner :octocat: …

Thanks for jumping in and updating the issue with your findings!

edojacobs commented 2 years ago

Workaround i found which worked for me is to use rollup and import rollup output file into jest to test the code. https://gist.github.com/edojacobs/9cfdcb016b77954daa2cbae5eaa34f24

NaumovEvgeniy commented 2 years ago

Hi! Anybody solve the problem with the mocha? I use mocha via ts-node. I've faced with the followng problem

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

My test case is

import {Vector3} from "@babylonjs/core/Maths/math.vector";

describe('VCamera' , function (){
  it('test', () => {
    new Vector3()
  })
});

My config .mocharc.json

{
  "require": ["ts-node/register", "tsconfig-paths/register", "./.mocha.register.js"]
}
PhilippeMorier commented 2 years ago

In my case transformIgnorePatterns doesn't seem to work. I'm in a nx monorepo.

A solution which works for me is to install the ES5 version of babylonjs as a devDependencies and map @babylonjs to babylonjs in jest.preset.js.

const nxPreset = require('@nrwl/jest/preset').default;

module.exports = {
  ...nxPreset,
  moduleNameMapper: {
    '@babylonjs': 'babylonjs',
  },
};

Seems not optimal :shrug:. Can anybody see a down-side of it?

RaananW commented 2 years ago

I really want to see it reproduced. Care to share a minimal project?

PhilippeMorier commented 2 years ago

I created this stackblitz.

I hope this shows the issue. It's a minimal nx workspace with an Angular app and Babylon.js as a dependency.

I am not sure if I set the correct pattern in transformIgnorePatterns in jest.config.ts. If you could verify the pattern that would be awesome :muscle:.

Please, make sure

This should show you SyntaxError: Cannot use import statement outside a module.

RaananW commented 2 years ago

I get this:

image

So it's hard for me to fully test this configuration.

Eventually, you need to make sure everything is transpiled to the right syntax. Babylon's latest 5.X version is delivered in ES2021 syntax, so you might want to pass it through babel to make sure jest accepts its syntax.

PhilippeMorier commented 2 years ago

Hm... I don't get it how there is a different result even tough it's the same Stackblitz 🤔 🤦‍♂️ .

I've pinned the versions and regenerated the package-lock.json, but I guess you're still getting the same error?

Do you run the project directly on Stackblitz in the WebContainer?

RaananW commented 2 years ago

I just used the link you provided and followed your steps. I don't know stackblitz good enough to tell you what I using (or not) :-)

PhilippeMorier commented 6 months ago

Sorry, to bring this up again. I think it would be interesting to understand the issue. Especially, the fact that you seem to get a different result even tough we use the same Stackblitz :sweat_smile:.

I just open the Stackblitz again and could reproduce the issue. Therefore, I just want to double check that we do the same thing. This is what I see/get.

image