Closed baltpeter closed 2 months ago
Here's the code that causes this problem. We're trying to find appstraction
's version by importing its package.json
:
I think that problem is that cli
is using tsc
instead of a "proper" bundler like Parcel.
And Node does not support importing JSON files without an import assertion (require()
works fine, though).
I tried this example:
import abc from './abc.json';
console.log(abc);
And indeed:
❯ node index.mjs
node:internal/errors:496
ErrorCaptureStackTrace(err);
^
TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///tmp/sdfsdfsd/abc.json" needs an import assertion of type "json"
at new NodeError (node:internal/errors:405:5)
at validateAssertions (node:internal/modules/esm/assert:94:15)
at defaultLoad (node:internal/modules/esm/load:93:3)
at DefaultModuleLoader.load (node:internal/modules/esm/loader:263:26)
at DefaultModuleLoader.moduleProvider (node:internal/modules/esm/loader:179:22)
at new ModuleJob (node:internal/modules/esm/module_job:63:26)
at #createModuleJob (node:internal/modules/esm/loader:203:17)
at DefaultModuleLoader.getJobFromResolveResult (node:internal/modules/esm/loader:156:34)
at DefaultModuleLoader.getModuleJob (node:internal/modules/esm/loader:141:17)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:33) {
code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING'
}
Node.js v20.5.1
Earlier versions (like Node 14) didn't support importing JSON files at all:
❯ nvm use 14
Now using node v14.21.2 (npm v6.14.17)
❯ node index.mjs
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /tmp/sdfsdfsd/abc.json
at new NodeError (internal/errors.js:322:7)
at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)
at Loader.getFormat (internal/modules/esm/loader.js:105:42)
at Loader.getModuleJob (internal/modules/esm/loader.js:243:31)
at async ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:78:21)
at async Promise.all (index 0)
at async link (internal/modules/esm/module_job.js:83:9) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
The problem is the interaction between tsc
and Parcel.
If I bundle the example from above using tsc
(npx typescript index.ts --resolveJsonModule --esModuleInterop
), it produces:
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var abc_json_1 = __importDefault(require("./abc.json"));
console.log(abc_json_1.default);
Meanwhile, Parcel keeps this as a JSON import:
import {version as $kYxtx$version} from "appstraction/package.json";
I had a similar problem in ReportHAR.
Unfortunately, just adding the import assertion didn't help—Parcel "helpfully" strips those in the output.
In ReportHAR, I was able to work around the problem by using Parcel's bundle inlining feature to… well, inline the JSON into the bundled code.
But I don't think that that is a valid solution here. That would mean that we essentially hardcode the appstraction
version at build time. But that may not be the version that actually runs on the enduser's PC.
The problem is the interaction between
tsc
and Parcel.
Actually, that description doesn't quite describe the problem correctly. The reason that tsc
produced CJS code in this example is that I ran it with a blank tsconfig.json
and only supplied the resolveJsonModule
and esModuleInterop
via the command line.
If we repeat a similar experiment with cli
's tsconfig.json
(which is configured to output ESM: "target": "es2019"
), it will also just preserve JSON imports:
import test from './test.json';
Running the output with node
produces the same ERR_IMPORT_ASSERTION_TYPE_MISSING
error.
Whether it preserves import assertions depends on the module
option, which gets a lot more complicated. But I won't get into that, because all of this is beside the point, I was just correcting what I had said earlier.
I think the actual issue here is that the JSON import is in dependency. And tsc
will just never touch those at all. So, the tsconfig.json
settings and whatever tsc
produces, don't even matter at all.
This is turning out surprisingly hard.
npm
commands.I have seen various suggestions to read the dependency's package.json
using readFile()
but that also brings a whole host of problems:
How do I even find appstraction
's package.json
? I can't just read from CA's node_modules
because appstraction
won't be there if CA is itself a dependency in some other module:
NPM/yarn will flatten the node_modules
. But I'm not even sure if that is standardised and we can rely on that.
import.meta.resolve()
would work but according to MDN it's only supported from Node 20.6, whereas we specifically require Node 18 because of Frida.Oh, looks like someone has very kindly reimplemented the whole module resolution algorithm in a module: https://github.com/wooorm/import-meta-resolve!
While it's utterly ridiculous that we need something like that, this seems like the best solution to me.
The only other alternative that I had in mind was shipping a single .cjs
file with require('appstraction/package.json').version)
.
That seems to work.
But of course, it won't work for getting our own version. So I guess, we will still need bundle inlining. sigh
Urgh, now bundle inlining isn't working for some reason. -.-
Welp, import-meta-resolve
doesn't work either if I install CA as a dependency:
Error: Cannot find package 'appstraction' imported from /src/util.ts
Code: ERR_MODULE_NOT_FOUND
I'm wasting way too much time on this. CJS shim it is.
CJS shim doesn't work (trivially, at least) because Parcel helpfully folds that into the ESM module as:
var $e16ea7c30f77cffa$exports = {};
$e16ea7c30f77cffa$exports = {
/**
* @param {string} dependency
*
* @returns {Promise<string>}
*/ getDependencyVersion: async (dependency)=>{
if (dependency === "cyanoacrylate") dependency = "..";
return require(`${dependency}/package.json`).version;
}
};
And that obviously fails with require is not defined
.
@baltpeter @zner0L Is there anything we con do about that issue or is somebody working on it? Right now i am getting the same issue with the newest version of tweasel-cli (see below). I am wondering if there is currently any working version of tweasel when trying to get an fresh version. If I use npm to install it I get an frida/meson build error (see my open thread at tweasel-cli-site) and when I install tweasel 1.0.1 via yarn I run into this error. I even tried some older Versions of tweasel but then I run into the problem, that the auto-configuration of Wireguard doesnt work. So any Ideas or help? Would be great! Thanks in Advance.
`
tweasel Command-line tool for the libraries of the tweasel project.
VERSION tweasel-cli/1.0.1 linux-x64 node-v18.20.4
USAGE $ tweasel [COMMAND]
TOPICS android-emulator Create, start, and delete Android emulators.
COMMANDS autocomplete display autocomplete installation instructions detect-tracking Detect tracking data transmissions from traffic in HAR format. help Display help for tweasel. record-traffic Record the traffic of an Android or iOS app in HAR format.
:~$ tweasel record-traffic '/home/apppruefung/Schreibtisch/com.lidl.eci.lidlplus_16.8.2-1470400597.apk' TypeError: Module "file:///home/apppruefung/.nvm/versions/node/v18.20.4/li b/node_modules/tweasel-cli/node_modules/appstraction/package.json" needs an import attribute of type "json" Code: ERR_IMPORT_ASSERTION_TYPE_MISSING
`
Found a workaround for now - but it should definitly be fixed in future. In the file /usr/local/share/.config/yarn/global/node_modules/cyanoacrylate/dist/index.js
you can delete the line import {version as $kYxtx$version} from "appstraction/package.json";
and change the lines
const versions = { appstraction: (0, $kYxtx$version), cyanoacrylate: (0, $d3eb50877c24837a$exports.version),
to
const versions = { appstraction: (0, "1.3.0"), cyanoacrylate: (0, "1.2.0"),
I tried upgrading
cli
to the latest CA version. However, when trying to build, I get the following error: