#[External SyntaxError] Unable to import npm package into SvelteKit project

158 messages · Page 1 of 1 (latest)

crystal spear
#

Trying to import esptool-js ( https://github.com/espressif/esptool-js )

Getting this weird Unexpected token error, tried to debug for 2 days, getting nowhere, this is easily reproducable:

import type { IEspLoaderTerminal } from 'esptool-js'; // No error
import { type IEspLoaderTerminal } from 'esptool-js'; // All hell breaks loose
10:48:53 PM [vite] Error when evaluating SSR module /src/lib/components/EspTool/FlashManager.ts: failed to import "esptool-js"
|- F:\Development\Source\MyProject\Frontend\node_modules\esptool-js\lib\index.js:1
export { ESPLoader } from "./esploader";
^^^^^^

SyntaxError: Unexpected token 'export'
    at internalCompileFunction (node:internal/vm:77:18)
    at wrapSafe (node:internal/modules/cjs/loader:1288:20)
    at Module._compile (node:internal/modules/cjs/loader:1340:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at cjsLoader (node:internal/modules/esm/translators:356:17)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:305:7)
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
GitHub

Javascript implementation of flasher tool for Espressif chips, running in web browser using WebSerial. - GitHub - espressif/esptool-js: Javascript implementation of flasher tool for Espressif chips...

past violet
#

export { ESPLoader } from "./esploader";
^^^^^^

SyntaxError: Unexpected token 'export'
at internalCompileFunction (node:internal/vm:77:18)
at wrapSafe (node:internal/modules/cjs/loader:1288:20)
is pretty clear

#

node is trying to import that module in commonjs mode, but it is an ESM-only module
so it will fail

#

@crystal spear

crystal spear
#

How can I solve this @past violet ? thinkeyes

past violet
#

well, what is your current TS config exactly?

crystal spear
#

my package.json is set to module

past violet
#

are you using Vite?

crystal spear
#

yup

past violet
#

what preset/template?

crystal spear
#
{
    "extends": "./.svelte-kit/tsconfig.json",
    "compilerOptions": {
        "allowJs": true,
        "checkJs": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "resolveJsonModule": true,
        "skipLibCheck": true,
        "sourceMap": true,
        "strict": true,
        "moduleResolution": "bundler"
    }
}
past violet
#

and what does .svelte-kit/tsconfig.json look like?

crystal spear
#
{
    "compilerOptions": {
        "paths": {
            "$lib": [
                "../src/lib"
            ],
            "$lib/*": [
                "../src/lib/*"
            ]
        },
        "rootDirs": [
            "..",
            "./types"
        ],
        "verbatimModuleSyntax": true,
        "isolatedModules": true,
        "lib": [
            "esnext",
            "DOM",
            "DOM.Iterable"
        ],
        "moduleResolution": "bundler",
        "module": "esnext",
        "noEmit": true,
        "target": "esnext"
    },
    "include": [
        "ambient.d.ts",
        "non-ambient.d.ts",
        "./types/**/$types.d.ts",
        "../vite.config.js",
        "../vite.config.ts",
        "../src/**/*.js",
        "../src/**/*.ts",
        "../src/**/*.svelte",
        "../tests/**/*.js",
        "../tests/**/*.ts",
        "../tests/**/*.svelte"
    ],
    "exclude": [
        "../node_modules/**"
    ]
}
past violet
#

everything looks normal to me so far

#

isn't there a node tsconfig file as well?

crystal spear
#

yeah, my thought exactly thinkingHD

#

hm?

past violet
crystal spear
#

This is compiled as a static site, no server-side js

past violet
#

wait, svelte-ts or svelte-kit preset?

crystal spear
#

svelte-kit

past violet
#

that's not a Vite project, right?

crystal spear
#

it is

past violet
#

you just happen to use vite to ssr your site

#

but it's not a base Vite template

#

you didn't use Vite to scaffold your project

#

it's just a normal svelte-kit project

crystal spear
#
npm create svelte@latest my-app
cd my-app
npm i -D esptool-js
#

and then try to use it

crystal spear
#

i changed it to use @sveltejs/adapter-static

crystal spear
#

well full setup i did looks like this:
skeleton scaffolder -> sveltekit scaffolder -> vite scaffolder

past violet
#

ok, I have no clue how Svelte and SvelteKit work, and how the library works either

#

but installed the deps, imported some stuff from the lib

#

and while serving the site in dev mode, I don't have any import problems

#

building the app worked as well

#

only thing to notice is that verbatimModuleSyntax is enabled by default, so you can only import IEspLoaderTerminal by using a type-only import

crystal spear
#

hmm

#

you diffed our package and tsconfig?

#

imma try to create a brand new project

past violet
#

I didn't change any of the default

#

and everything you've shared so far is similar to what I have

crystal spear
#

My package.json:

#
{
    "name": "frontend",
    "version": "0.0.1",
    "private": true,
    "scripts": {
        "dev": "vite dev",
        "build": "vite build",
        "preview": "vite preview",
        "test": "npm run test:integration && npm run test:unit",
        "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
        "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
        "lint": "prettier --check . && eslint .",
        "format": "prettier --write .",
        "test:integration": "playwright test",
        "test:unit": "vitest"
    },
    "devDependencies": {
        "@microsoft/signalr": "^8.0.0",
        "@playwright/test": "^1.28.1",
        "@sentry/svelte": "^7.86.0",
        "@skeletonlabs/skeleton": "2.7.1",
        "@skeletonlabs/tw-plugin": "0.3.1",
        "@sveltejs/adapter-static": "^3.0.1",
        "@sveltejs/kit": "^2.0.0",
        "@sveltejs/vite-plugin-svelte": "^3.0.0",
        "@tailwindcss/forms": "0.5.7",
        "@tailwindcss/typography": "0.5.10",
        "@types/crypto-js": "^4.2.2",
        "@types/eslint": "8.56.0",
        "@types/node": "20.11.5",
        "@types/w3c-web-serial": "^1.0.6",
        "@typescript-eslint/eslint-plugin": "^6.0.0",
        "@typescript-eslint/parser": "^6.0.0",
        "autoprefixer": "10.4.17",
        "bowser": "^2.11.0",
        "crypto-js": "^4.2.0",
        "eslint": "^8.56.0",
        "eslint-config-prettier": "^9.1.0",
        "eslint-plugin-svelte": "^2.35.1",
        "esptool-js": "^0.3.2",
        "postcss": "8.4.33",
        "prettier": "^3.1.1",
        "prettier-plugin-svelte": "^3.1.2",
        "svelte": "^4.2.7",
        "svelte-check": "^3.6.0",
        "tailwindcss": "3.4.1",
        "tslib": "^2.4.1",
        "typescript": "^5.0.0",
        "vite": "^5.0.3",
        "vite-plugin-tailwind-purgecss": "0.2.0",
        "vitest": "^1.2.0"
    },
    "type": "module",
    "dependencies": {
        "@floating-ui/dom": "1.5.4",
        "highlight.js": "11.9.0"
    }
}
#

im setting one up from scratch rn

#

trying to reproduce issue

past violet
crystal spear
#

ok

#

@past violet

#

i reproduced it

#

give me a min

#
npm create skeleton-app@latest my-skeleton-app
cd .\my-skeleton-app\
npm i -D esptool-js @types/w3c-web-serial

routes/+page.svelte

<script lang="ts">
    import { ESPTest } from '$lib';
</script>

<p>test: {ESPTest()}</p>

lib/index.ts

import { ESPLoader, Transport, type LoaderOptions } from 'esptool-js';

export async function ESPTest() {
    const port = await navigator.serial.requestPort();

    const transport = new Transport(port);

    const flashOptions = {
        transport,
        baudrate: 115200
    } as LoaderOptions;

    const loader = new ESPLoader(flashOptions);

    return { loader, transport };
}
npm run dev
#

what node version are you on?

past violet
#

@crystal spear if you switch to the adapter-static adapter, and copy the recommended config, everthing works again

crystal spear
#

the recommended config?

past violet
#
import adapter from '@sveltejs/adapter-static';

export default {
    kit: {
        adapter: adapter({
            // default options are shown. On some platforms
            // these options are set automatically — see below
            pages: 'build',
            assets: 'build',
            fallback: undefined,
            precompress: false,
            strict: true
        })
    }
};
#

...and add the prerender option to your root layout:

#

Before you can deploy your SvelteKit app, you need to adapt it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment.

crystal spear
#

hm doesnt seem to be working

#

deleting .svelte-kit folder and trying again

past violet
#

did you restart the dev server?

crystal spear
#

yup

past violet
#

wait, now I have it building using the default adapter-auto

crystal spear
past violet
#

I guess installing @sveltejs/adapter-static did fit it

#

even tho I'm not actively using it

#

just make sure you actually have one adapter for your target

crystal spear
#

mhm using static atm

#

them tried to open in browser, and it all fails

past violet
#

wait, it's very inconsitent

#

one time it builds no problem

#

and if I run the same command again it doesn't work suddenly

#

oh, actually
starting the dev server works, but when you actually go on to the page, it tries to compile that bit and fails

crystal spear
#

mhm

#

just run the build command

#

seems to be more consise

past violet
#

import { Transport, ESPLoader } from "esptool-js";
^^^^^^^^^
SyntaxError: Named export 'ESPLoader' not found. The requested module 'esptool-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 'esptool-js';
const { Transport, ESPLoader } = pkg;

#

wait, I think I know

#

could be that the lib is just broken?

#

it's detected as CJS, but in reality the lib is ESM

crystal spear
#

i hope not

past violet
#

that's simply because the authors forgot to set type: "module" in the package.json

crystal spear
#

someone as big as Espressif just....

#

forgot?

past violet
#

guess it really depends on the bundler you use and how they check for CJS/ESM

crystal spear
#

is there any way i can just

#

fork and npm it myslef

#

a pr would take weeks

past violet
#

you could patch the lib locally, but not 100% this is the problem in the 1st place

crystal spear
#

are we completely sure?

past violet
crystal spear
past violet
#

you should explain the problem you are facing and why your solution is the correct way of doing things
rather than simply opening a PR and expecting it to be merged asap without providing any extra info

crystal spear
#

will do

#

does this issue happen in sveltekit?

#

or vite?

#

i want to narrow it down

#

minimal example

past violet
#

also "type": "module" is still node-specific iirc
so no clue what they are trying to achieve, comply with ecmascript standards? or node-compliant? etc.

past violet
#

your project uses SvelteKit, SvelteKit uses Vite, Vite uses esbuild
and esbuild is trying to bundle esptool-js but using the wrong file

crystal spear
#

honestly I dont have enough knowledge to write a proper PR on this

#

esbuild is at the very bottom of this got it

past violet
#

but esbuild isn't the problem

crystal spear
#

the library decleration is?

past violet
#

not sure

#

providing main, module, and browser should be enough

#

and the bundler should be able to pick the right file

#

but here it's picking the wrong one, or at least is expecting a different module system for the one it picks

crystal spear
#

is this related?

past violet
#

not sure if statically building the website makes the compiler swicth to CJS or something

past violet
#

there, the real difference was browser env vs. ESM

#

here we'd like to know why it thinks the module is "CJS"

#

maybe passing additional debug flags to esbuild when building would help

crystal spear
#

how would we do that? xd

past violet
#

but anyway, there is still something a bit wrong with that library
because of the main property pointing to an ESM file inside of a CJS, like it would normally be the case for node

#

probably messes with the bundler

crystal spear
#

hm...

crystal spear
#

i dont see that

crystal spear
#

@past violet I have a really cursed fix

#

Im going to do a pre-build script

#

Goes in and modifies the node package

#

Adds type: module

#

And renames files to .mjs

past violet
#

does it work?

crystal spear
#

Idk yet

#

Just thought of it

#

I hate this with a passion

crystal spear
#
#

Imma use this

crystal spear
#

@past violet i fixed it

#

esptool-js+0.3.2.patch

diff --git a/node_modules/esptool-js/lib/esploader.js b/node_modules/esptool-js/lib/esploader.js
index fe979ac..3ac57ce 100644
--- a/node_modules/esptool-js/lib/esploader.js
+++ b/node_modules/esptool-js/lib/esploader.js
@@ -1,7 +1,7 @@
-import { ESPError } from "./error";
+import { ESPError } from "./error.js";
 import { deflate, Inflate } from "pako";
-import { Transport } from "./webserial";
-import { customReset, usbJTAGSerialReset } from "./reset";
+import { Transport } from "./webserial.js";
+import { customReset, usbJTAGSerialReset } from "./reset.js";
 async function magic2Chip(magic) {
     switch (magic) {
         case 0x00f01d83: {
diff --git a/node_modules/esptool-js/lib/index.js b/node_modules/esptool-js/lib/index.js
index c4e4046..9e97eef 100644
--- a/node_modules/esptool-js/lib/index.js
+++ b/node_modules/esptool-js/lib/index.js
@@ -1,2 +1,2 @@
-export { ESPLoader } from "./esploader";
-export { Transport } from "./webserial";
+export { ESPLoader } from "./esploader.js";
+export { Transport } from "./webserial.js";
diff --git a/node_modules/esptool-js/package.json b/node_modules/esptool-js/package.json
index 5cbd77d..d55fe74 100644
--- a/node_modules/esptool-js/package.json
+++ b/node_modules/esptool-js/package.json
@@ -1,6 +1,7 @@
 {
   "name": "esptool-js",
   "version": "0.3.2",
+  "type": "module",
   "module": "lib/index.js",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
#

and then just run

#

npx patch-package

#

its horrible

#

but

past violet
#

yeah, idk, the package is kinda broken in the first place

#

maybe just open a GH issue to ask with they didn't set the type: "module" and used proper ES imports with the file extension, as required by the node-esm syntax

crystal spear
#

i already did