Skip to content

Crash when running a ES6 JakefileΒ #415

@laurentb-roy

Description

@laurentb-roy

Step to reproduce

  1. Create a new project, install jake
  2. Add the follow in package.json: "type": "module"
  3. Write the following Jakefile.js
import fs from 'fs';

task('default', () => {
    console.log('Task ran');
});
  1. Run jake: ./node_modules/.bin/jake
  2. The following error is displayed
jake aborted.
Error [ERR_REQUIRE_ESM]: require() of ES Module .../jakefile.js from .../node_modules/jake/lib/loader.js not supported.
Instead change the require of jakefile.js in .../node_modules/jake/lib/loader.js to a dynamic import() which is available in all CommonJS modules.
    at loadFile (.../node_modules/jake/lib/loader.js:67:20)
    at Loader.loadFile (.../node_modules/jake/lib/loader.js:141:7)
    at EventEmitter.Object.assign.run (.../node_modules/jake/lib/jake.js:315:37)
    at Object.<anonymous> (.../node_modules/jake/bin/cli.js:31:10)

Investigation

It seems the problem is that the Jakefile is loaded via the old, synchronous require() call. Offending line:

In Jake source code, lib/loader.js:66

  function loadFile(filePath) {
    let exported = require(filePath); // <------ Problem here
    for (let [key, value] of Object.entries(exported)) {
      let t;
      if (typeof value == 'function') {
        t = jake.task(key, value);
        t.description = '(Exported function)';
      }
    }
  }

Node.js does not support importing an ES6 module with this call, only commonjs module.

Potential fix

The fix is to use an asynchronous import() expression, which can import ES6 module from commonjs. However, that would making the function loadFile() and all its caller asynchronous, so its not a one line replacement.

Import expression: https://nodejs.org/dist/latest-v16.x/docs/api/esm.html#import-expressions

There is a little guide explaining the details here: https://techsparx.com/nodejs/esnext/esmodules-from-commonjs.html

Workaround

You can rename the Jakefile.js to Jakefile.cjs and rewrite it to use commonjs import

fs = require('fs');

task('default', () => {
    console.log('BUILD DONE');
});

You will need to specify the jakefile explicitely : ./node_modules/.bin/jake -f Jakefile.cjs

Of course, if you import any ES6 module from Jakefile.cjs, you will need to use import expression, which can be cumbersome to use.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions