use ES6 import modules with pkg

Viewed 2473

I'm trying to package a node app as an exe using pkg, and I'd like to use ES6 imports.

I have something like this in my src/app.js:

import express from 'express'
const app = express()

const eco = (req, res) => {
  const { method, url, headers, query } = req
  res.json({ method, url, headers, query })
}

app.all('/', eco)

app.listen(3000, () => console.log(`listening on http://localhost:3000`))

in my package.json I have:

{
  "name": "pkg-test",
  "version": "1.0.0",
  "description": "",
  "main": "src/app.js",
  "type": "module",
  "type": "module",
  "scripts": {
"build": "pkg --targets=node12-win-x64 --output=iisnode-pkg.exe --options experimental-modules src/app.js",
    "start": "node --experimental-modules src/app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "pkg": "^4.4.0"
  }

}

npm start works fine

$ npm start

> iisnode-pkg@1.0.0 start C:\data\devel\apps\tmp\iisnode-pkg
> node --experimental-modules src/app.js

(node:10668) ExperimentalWarning: The ESM module loader is experimental.
welcome to iisnode-pkg
iisnode-pkg listening on http://localhost:3000

but npm run build gives a waning and then running the exe throws an error:

>npm run build

> iisnode-pkg@1.0.0 build C:\data\devel\apps\tmp\iisnode-pkg
> pkg --targets=node12-win-x64 --output=iisnode-pkg.exe src/app.js --config package.json

> pkg@4.4.0
> Warning Failed to make bytecode node12-x64 for file C:\snapshot\iisnode-pkg\src\app.js
>iisnode-pkg.exe
C:\snapshot\iisnode-pkg\src\app.js:2
import express from 'express'
       ^^^^^^^

SyntaxError: Unexpected identifier
    at Module._compile (internal/modules/cjs/loader.js:701:23)
    at Module._compile (pkg/prelude/bootstrap.js:1268:32)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:768:10)
    at Module.load (internal/modules/cjs/loader.js:626:32)
    at Function.Module._load (internal/modules/cjs/loader.js:553:12)
    at Function.Module.runMain (pkg/prelude/bootstrap.js:1316:12)
    at internal/main/run_main_module.js:17:11

It seems like the --options experimental-modules parameter from the build script in package.json is not beign taken into account.

Any idea how can I use ES6 module imports from a node app packaged with pkg?

3 Answers

I'll post an update if I find a resolution but this no longer seems possible.

ESM modules are no longer experimental, they are a core part of Node and the recommended convention to use.

Given a simple test, the current pkg generates a warning that results in ESM module files being skipped with this error, so at runtime the module cannot be loaded. I am not sure when this broke, but I have posted a simple reproduction of the problem here: https://github.com/appurist/pkgtest/

I've also added a comment on the (closed) GitHub issue here: https://github.com/vercel/pkg/issues/641#issuecomment-870013906

There doesn't appear to be any workaround as the problem seems to be in pkg itself.

You will have to first convert the ESM to Commonjs. You can use babel/preset-env for this. Then afterwards use pkg to build the exe from the generated Commonjs.

Here is a snippet from my package.json.

   ...
  "main": "index.js",
  "type": "module",
  "scripts": {
    "convert": "babel src -d lib",
    "test": "jest",
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "build": "npm run convert && pkg ./lib/index.js --target node16-win-x64 -o build/SGMS-API.exe"
  },
 "devDependencies": {
    "@babel/cli": "^7.18.10",
    "@babel/core": "^7.18.10",
    "@babel/preset-env": "^7.18.10",
    "@jest/globals": "^28.1.3",
    "pkg": "^5.8.0"
  }

And here is my babel.config.json

{
    "presets": ["@babel/preset-env"]
}

This is a good starting point for babel: https://babeljs.io/setup#installation

Related