5

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

> [email protected] 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

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

> [email protected]
> 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?

2

3 Answers 3

7

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.

Sign up to request clarification or add additional context in comments.

1 Comment

1

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

Comments

0

Make sure you're running a pretty recent version of Node. The implementation of ESM in Node.js changed in version 12.0.0. "type": "module" wasn't supported in 10.x.

You need to add options to the pkg configuration. So, in package.json:

"pkg": {
    "options": ["experimental-modules"]
}

Node documentation: https://nodejs.org/api/esm.html

2 Comments

Is this still valid? I would love to know how to place experimental-modules need in package.json, but the page you link to has no mention of pkg or options (other than command line options).
For anyone interested (and @akauppi maybe), the snippet would have to be inserted on top level in your package.json, e.g. below "name". However, this appears to make no difference at all, as per github.com/vercel/pkg/issues/1291 ESM modules are still not supported in pkg because it tries to load and wrap a CommonJS module. Therefore, you need to compile your code to CommonJS if you want to use pkg.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.