use ES6 import modules with pkg
Asked Answered
R

3

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?

Rafaellle answered 15/10, 2019 at 10:19 Comment(2)
github.com/vercel/pkg/issues/1291Chanukah
See my answer here: https://mcmap.net/q/1355945/-pkg-failed-to-make-bytecodeDinar
G
6

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.

Grievous answered 28/6, 2021 at 20:37 Comment(1)
github.com/vercel/pkg/issues/1291Chanukah
D
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

Dinar answered 4/8, 2022 at 13:57 Comment(0)
P
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

Polarize answered 23/10, 2019 at 13:24 Comment(2)
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).Hildehildebrand
For anyone interested (and @Hildehildebrand 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.Duren

© 2022 - 2024 — McMap. All rights reserved.