Skip to content

Commit

Permalink
New: Support ESM w/ mjs extension where available (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
snoack authored Jun 3, 2020
1 parent e2d7bce commit 15d0648
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 28 deletions.
28 changes: 28 additions & 0 deletions lib/shared/require-or-import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

var pathToFileURL = require('url').pathToFileURL;

var importESM;
try {
importESM = new Function('id', 'return import(id);');
} catch (e) {
importESM = null;
}

function requireOrImport(path, callback) {
var err = null;
var cjs;
try {
cjs = require(path);
} catch (e) {
if (pathToFileURL && importESM && e.code === 'ERR_REQUIRE_ESM') {
var url = pathToFileURL(path);
importESM(url).then(function(esm) { callback(null, esm); }, callback);
return;
}
err = e;
}
process.nextTick(function() { callback(err, cjs); });
}

module.exports = requireOrImport;
23 changes: 14 additions & 9 deletions lib/versioned/^3.7.0/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ var copyTree = require('../../shared/log/copy-tree');
var tildify = require('../../shared/tildify');
var logTasks = require('../../shared/log/tasks');
var ansi = require('../../shared/ansi');
var exit = require('../../shared/exit');
var logEvents = require('./log/events');
var logTasksSimple = require('./log/tasks-simple');
var registerExports = require('../../shared/register-exports');
var requireOrImport = require('../../shared/require-or-import');

function execute(opts, env, config) {
var tasks = opts._;
Expand All @@ -25,20 +27,23 @@ function execute(opts, env, config) {
}

// This is what actually loads up the gulpfile
var exported = require(env.configPath);
log.info('Using gulpfile', ansi.magenta(tildify(env.configPath)));
requireOrImport(env.configPath, function(err, exported) {
if (err) {
console.error(err);
exit(1);
}

var gulpInst = require(env.modulePath);
logEvents(gulpInst);
log.info('Using gulpfile', ansi.magenta(tildify(env.configPath)));

registerExports(gulpInst, exported);
var gulpInst = require(env.modulePath);
logEvents(gulpInst);

// Always unmute stdout after gulpfile is required
stdout.unmute();
registerExports(gulpInst, exported);

process.nextTick(function() {
var tree;
// Always unmute stdout after gulpfile is required
stdout.unmute();

var tree;
if (opts.tasksSimple) {
return logTasksSimple(env, gulpInst);
}
Expand Down
15 changes: 9 additions & 6 deletions lib/versioned/^4.0.0-alpha.1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var logTasksSimple = require('../^4.0.0/log/tasks-simple');
var registerExports = require('../../shared/register-exports');

var copyTree = require('../../shared/log/copy-tree');
var requireOrImport = require('../../shared/require-or-import');

function execute(opts, env, config) {

Expand All @@ -32,16 +33,18 @@ function execute(opts, env, config) {
logSyncTask(gulpInst, opts);

// This is what actually loads up the gulpfile
var exported = require(env.configPath);
requireOrImport(env.configPath, function(err, exported) {
if (err) {
console.error(err);
exit(1);
}

registerExports(gulpInst, exported);
registerExports(gulpInst, exported);

// Always unmute stdout after gulpfile is required
stdout.unmute();
// Always unmute stdout after gulpfile is required
stdout.unmute();

process.nextTick(function() {
var tree;

if (opts.tasksSimple) {
return logTasksSimple(gulpInst.tree());
}
Expand Down
15 changes: 9 additions & 6 deletions lib/versioned/^4.0.0-alpha.2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var registerExports = require('../../shared/register-exports');

var copyTree = require('../../shared/log/copy-tree');
var getTask = require('../^4.0.0/log/get-task');
var requireOrImport = require('../../shared/require-or-import');

function execute(opts, env, config) {

Expand All @@ -33,16 +34,18 @@ function execute(opts, env, config) {
logSyncTask(gulpInst, opts);

// This is what actually loads up the gulpfile
var exported = require(env.configPath);
requireOrImport(env.configPath, function(err, exported) {
if (err) {
console.error(err);
exit(1);
}

registerExports(gulpInst, exported);
registerExports(gulpInst, exported);

// Always unmute stdout after gulpfile is required
stdout.unmute();
// Always unmute stdout after gulpfile is required
stdout.unmute();

process.nextTick(function() {
var tree;

if (opts.tasksSimple) {
tree = gulpInst.tree();
return logTasksSimple(tree.nodes);
Expand Down
15 changes: 9 additions & 6 deletions lib/versioned/^4.0.0/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var registerExports = require('../../shared/register-exports');

var copyTree = require('../../shared/log/copy-tree');
var getTask = require('./log/get-task');
var requireOrImport = require('../../shared/require-or-import');

function execute(opts, env, config) {

Expand All @@ -33,16 +34,18 @@ function execute(opts, env, config) {
logSyncTask(gulpInst, opts);

// This is what actually loads up the gulpfile
var exported = require(env.configPath);
requireOrImport(env.configPath, function(err, exported) {
if (err) {
console.error(err);
exit(1);
}

registerExports(gulpInst, exported);
registerExports(gulpInst, exported);

// Always unmute stdout after gulpfile is required
stdout.unmute();
// Always unmute stdout after gulpfile is required
stdout.unmute();

process.nextTick(function() {
var tree;

if (opts.tasksSimple) {
tree = gulpInst.tree();
return logTasksSimple(tree.nodes);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"pretty-hrtime": "^1.0.0",
"replace-homedir": "^1.0.0",
"semver-greatest-satisfied-range": "^1.1.0",
"v8flags": "^3.0.1",
"v8flags": "^3.2.0",
"yargs": "^7.1.0"
},
"devDependencies": {
Expand Down
41 changes: 41 additions & 0 deletions test/esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

var expect = require('expect');
var fs = require('fs');
var path = require('path');
var semver = require('semver');
var skipLines = require('gulp-test-tools').skipLines;
var eraseTime = require('gulp-test-tools').eraseTime;
var runner = require('gulp-test-tools').gulpRunner;

var expectedDir = path.join(__dirname, 'expected');

if (semver.gte(process.version, '10.15.3')) {

describe('ESM', function() {

it('prints the task list', function(done) {
var options = '--tasks --sort-tasks ' +
'--gulpfile ./test/fixtures/gulpfiles/gulpfile.mjs';
var trailingLines = 1;
if (!semver.satisfies(process.version, '^12.17.0 || >=13.2.0')) {
options += ' --experimental-modules';
trailingLines += 2;
}

runner({ verbose: false }).gulp(options).run(cb);

function cb(err, stdout, stderr) {
expect(err).toEqual(null);
expect(stderr).toMatch(/^(.*ExperimentalWarning: The ESM module loader is experimental\.\n)?$/);
var filepath = path.join(expectedDir, 'esm.txt');
var expected = fs.readFileSync(filepath, 'utf-8');
stdout = eraseTime(skipLines(stdout, trailingLines));
expect(stdout).toEqual(expected);
done(err);
}
});

});

}
3 changes: 3 additions & 0 deletions test/expected/esm.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gulp-cli/test/fixtures/gulpfiles
├── exported
└── registered
10 changes: 10 additions & 0 deletions test/fixtures/gulpfiles/gulpfile.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import gulp from 'gulp';

function noop(cb) {
cb();
}

gulp.task('registered', noop);

export function exported(){};
export const string = 'no function';

0 comments on commit 15d0648

Please sign in to comment.