Moddable-OpenSource / moddable

Tools for developers to create truly open IoT products using standard JavaScript on low cost microcontrollers.
http://www.moddable.com
1.3k stars 236 forks source link

Unable to build TypeScript program using private scope modules #1363

Open cmidgley opened 2 weeks ago

cmidgley commented 2 weeks ago

Build environment: Windows (I believe any) Moddable SDK version: Requires recent version that supports private scope module build system changes Target device: Any

Description Private scope module resolution with Moddable requires an artificial path to create a common root (such as implemented by mcpack), which breaks TypeScript compilation. For example, to define the private scope package #example one might use a manifest.json containing a modules section similar to this:

"modules": {
    "root/main": "./src/main",
    "root/#example": "./src/example/index",
    "example/do-something": "./src/example/do-something"
}

The artificial path component root is used to assist module resolution in translating between the file system pathing of JS and the namespace resolution used in Moddable.

mcconfig then carries these artificial roots over to the generated tsconfig.json file:

"compilerOptions": {
    "paths": {
        "root/main": ["/some/path/main"],
        "root/#example": ["/some/path/example/index"],
        "example/do-something": ["/some/path/example/do-something"]
    }
}

This results in a TypeScript compilation error such as:

# tsc tsconfig.json
src/main.ts:1:29 - error TS2792: Cannot find module '#example'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?

1 import { doSomething } from '#example';
                              ~~~~~~~~~~

Steps to Reproduce

  1. Clone this repo
  2. Switch to the "typescript" branch
  3. Run mcconfig -m -d

Thoughts

I have not come up with an obvious/clean way to indicate to mcconfig that the root is artificial. While the best solution may be to change module resolution to not need artificial roots (easier to implement/understand for devs), that feels like a high-risk and low-reward endeavor. My solution has been to change the typescript / compiler option in manifest.json to run a small script that front-ends tsc and removes the artificial roots from tsconfig.json. This is working well for me, but it's a hack and not generic enough to be useful for others.

phoddie commented 2 weeks ago

Thanks for the example.

On macOS, the main branch works but the typescript branch fails as follows.

# tsc tsconfig.json
src/main.ts:1:29 - error TS2792: Cannot find module '#example'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?

1 import { doSomething } from '#example';

I assume this matches what you see. We'll take a look.

cmidgley commented 2 weeks ago

Yes, and this is because the tsconfig.json has the paths set to root/#module rather than what TypeScript needs which is just #module. My hack post-processor is a simple filter to remove the root/, but that isn't a great solution (though it works, so I'm not held up at all by this).