jakejs / jake

JavaScript build tool, similar to Make or Rake. Built to work with Node.js.
http://jakejs.com
Apache License 2.0
1.96k stars 190 forks source link

Using import in jakefile #386

Open pankajanand18 opened 3 years ago

pankajanand18 commented 3 years ago

I am running into an issue while using import in jakefile ,

My Jakefile

import {task, desc} from 'jake'; // using import instead of require 

desk("default");
task("default_task",()=>{
    console.log('default task running');
})

Error:

/Users/dummy/dev/test/jake/jake_es6_issue/jakefile.js:1
import {task, desc} from 'jake';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1053:16)
    at Module._compile (internal/modules/cjs/loader.js:1101:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)

I am pretty sure I am missing something really basic here. any help would be appreciated.

lubomirblazekcz commented 3 years ago

I guess you need nodejs 12+ and set "type": "module" in package.json

pankajanand18 commented 3 years ago

I guess you need nodejs 12+ and set "type": "module" in package.json

thanks for the response @evromalarkey . I tried that earlier but that didn't solve the problem. here is the error that i get.

➜  test node --version
v12.20.2
➜  test cat package.json
{
    "name": "jake-test",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "type":"module",
    "dependencies": {
    "jake": "^10.8.2"
}
}
➜  test npx jake -T  -f jakefile.js
Must use import to load ES Module: /Users/User/dev/test/jakefile.js
require() of ES modules is not supported.
require() of /Users/User/dev/test/jakefile.js from /Users/User/dev/test/node_modules/jake/lib/loader.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
    Instead rename jakefile.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/User/dev/test/package.json.

➜  test
lubomirblazekcz commented 3 years ago

Hmm no idea then, I just noticed this issue and wanted to help. I had this sort of issue with Gulp and type module solved it for me.

Too bad if Jake doesn't support ES6 import syntax, I was hoping for using it in the future.

pankajanand18 commented 3 years ago

Hmm no idea then, I just noticed this issue and wanted to help. I had this sort of issue with Gulp and type module solved it for me.

Too bad if Jake doesn't support ES6 import syntax, I was hoping for using it in the future.

No worries Mate. thanks for stopping by helping. I am sure I am making some small mistake here which can easily be rectified, i will wait for others to respond.

mendesds commented 3 years ago

Hello @pankajanand18 , I had the same problem here and found a solution. I don't know if it is the best way but it worked for me:

Install the @babel/register dependency:

npm install --save-dev @babel/registeror yarn add -D @babel/register

And in my jakelib folder I create the following file:

...
/Jakefile.js
/jakelib/task-example.js

My Jakefile.js file just have one line to initialize the @babel/register.

Jakefile.js

// Adding suport to ES6 modules
require("@babel/register");

And all my tasks I just use the ES6 modules syntax to import my files, as usual:

jakelib/task-example.js

import { task, desc }  from 'jake';
// your imports here

desc('This is the foo task.');
task('foo', () => {
  // your logic here
});
ajvincent commented 3 years ago

Here's another workaround:

const { fork } = require('child_process');

function runModule(pathToModule) {
  let resolve, reject;
  let p = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  const child = fork(pathToModule);
  child.on('exit', code => code ? reject(code) : resolve());

  return p;
}

let { task, desc } = require('jake');

desc("Testing");
task("test", async () => {
  await runModule("build-targets/test.mjs");
});

Probably not ideal, but unless Jake exposes a ECMAScript module, this might be the best I can do.

pankajanand18 commented 3 years ago

@mendesds I tried your approach but still getting the same error. Here is the repo to reproduce it: https://github.com/pankajanand18/jake-es6-problem

pankajanand18 commented 3 years ago

Here's another workaround:

const { fork } = require('child_process');

function runModule(pathToModule) {
  let resolve, reject;
  let p = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  const child = fork(pathToModule);
  child.on('exit', code => code ? reject(code) : resolve());

  return p;
}

let { task, desc } = require('jake');

desc("Testing");
task("test", async () => {
  await runModule("build-targets/test.mjs");
});

Probably not ideal, but unless Jake exposes a ECMAScript module, this might be the best I can do.

thanks @ajvincent , i will try this approach. We have 100 of different tasks imported as npm modules, it would be difficult to apply all those through this though.

ajvincent commented 3 years ago

thanks @ajvincent , i will try this approach. We have 100 of different tasks imported as npm modules, it would be difficult to apply all those through this though.

For a live example in a project I'm crafting now, see https://github.com/ajvincent/composite-collection/blob/main/Jakefile . It works surprisingly well, if the subsidiary modules are command-line modules with argparse.

Debugging via Chrome Developer Tools is particularly nice. The child processes just slide right in as if they were part of the parent Jake process. I mean, you don't even notice that it's in a child process.