2

I am trying to transfer an old node-express project over to be able to use es6. I have seen many posts about using gulp with es6. Most of them discuss using a syntax like this:

const gulp = require("gulp");
const babel = require("gulp-babel");

gulp.src('./index.js')
  .pipe(
    babel({
      presets: [
        ["@babel/env", { modules: false }],
      ],
    })
  )

However my existing project's gulpfile does't use gulp.src at all. Instead, it uses gulp-develop-server. The gulpfile looks like this:

const gulp = require("gulp");
const devServer = require("gulp-develop-server");
const spawn = require("child_process").spawn;
const fs = require("fs");

const basedir = ".";

function serverRestart(done) {
  // perform some cleanup code here
  devServer.restart();
  done();
}

function serverStart() {
  devServer.listen({
    path: basedir + "/index.js",
  });
}

function serverWatch() {
  serverStart();
  gulp.watch(
    [
      basedir + "/paths/**/*",
      // more directories to watch
    ],
    serverRestart
  );
}

function reload(done) {
  serverWatch();
  done();
}

function defaultTask() {
  let p;
  gulp.watch(["gulpfile.js"], killProcess);
  spawnChild();
  function killProcess(e) {
    if (p && !p.killed) {
      devServer.kill();
      p.kill("SIGINT");
      spawnChild();
    }
  }
  function spawnChild() {
    p = spawn("gulp", ["reload"], { stdio: "inherit" });
  }
}

process.stdin.resume();
process.on("exit", handleExit.bind(null, { cleanup: true }));
process.on("SIGINT", handleExit.bind(null, { exit: true }));
process.on("uncaughtException", handleExit.bind(null, { exit: true }));

function handleExit(options, err) {
  // perform some cleanup code here

  if (options.cleanup) {
    devServer.kill();
  }
  if (err) {
    console.log(err.stack);
  }
  if (options.exit) {
    process.exit();
  }
}

gulp.task("serverRestart", serverRestart);
gulp.task("serverStart", serverStart);
gulp.task("serverWatch", serverWatch);
gulp.task("reload", reload);
gulp.task("default", defaultTask);

The existing flow is important because it executes needed code for setup and cleanup every time I hit save, which runs serverRestart. I've been trying a few different methods based on the other questions which recommended using gulp.src().pipe(), but I havne't had much luck integrating it with the existing pattern which uses gulp-develop-server. I am trying to not have to rewrite the whole gulpfile. Is there a simple way to integrate babel with my existing gulpfile such that I can use es6 in my source code?

Seth Lutske
  • 9,154
  • 5
  • 29
  • 78

1 Answers1

1

There's an example with CoffeeScript in the gulp-develop-server documentation.

Using that as a model, try this:

function serverStart() {
  devServer.listen({
    path: "./dist/index.js",
  });
}

function serverWatch() {
  serverStart();
  gulp.watch(
    [
      basedir + "/paths/**/*",
    ],
    serverRestart
  );
}


function serverRestart() {
  gulp.src('./index.js')
    .pipe(
      babel({
        presets: [
          ["@babel/env", { modules: false }],
        ],
      })
    )
    .pipe( gulp.dest( './dist' ) )
    .pipe( devServer() );
}

Other suggestions

That being said, your existing Gulp file doesn't actually really use Gulp. That is, everything is defined as a function and it doesn't leverage any of Gulp's useful features, like managing task dependencies. This is because (pre-es6), this was a very simple project. The Gulp tasks in that file are an over-elaborate way to watch files and run a server. The same could be done (with less code) using nodemon.

With the introduction of React and more complicated build processes, Gulp seems to have fallen out of favor with the community (and in my personal experience, Gulp was a time sinkhole anyhow).

If the main change you want to make is to use import, you can simply use a more recent Node version. You'll surely run into the error SyntaxError: Cannot use import statement outside a module. Simply rename the file to .mjs and it will work. This provides a way to incrementally migrate files to import syntax. Other features should automatically work (and are all backwards-compatible, anyhow). Once your project is mostly, or all, compliant, you can add "type": "module" to your package.json file, then rename all of your require-style js files to .cjs, and rename all of your .mjs files to .js, or leave them as .mjs. Read more about the rules of mixing CommonJS and Module imports in the Node.js blog post (note that some things may have changed since that article was written).

Codebling
  • 10,764
  • 2
  • 38
  • 66
  • 1
    Maybe I was a little triggerhappy with the bounty. This is actually not working. I still get `SyntaxError: Cannot use import statement outside a module` when I start up the server. I realize this is because we are piping babel on restart, but not on start. I tried adding the same code into the `serverStart` function. With that, the server never truly starts, and the process doesn't reload on saving files. The only code that seems to be run is the `handleExit` code. Any thoughts? – Seth Lutske Jan 05 '22 at 20:10
  • As far as webpack and parcel go, those are typically front end bundlers. I'm not sure how simple it would be to retrofit those to a nodejs expressjs application. I tried shifting over to nodemon, which I've used before, but I ran into this issue: [Babel and Node - No stack trace on syntax errors](Babel and Node - No stack trace on syntax errors) – Seth Lutske Jan 05 '22 at 20:11
  • In general, don't need babel for ES6, unless you're using some very specific features (check the compatibility table at [node.green](https://node.green/)). Use a more recent version of Node unless you have a really good reason not to. – Codebling Jan 05 '22 at 21:10
  • For the SyntaxError, you can add ` "type": "module",` to your package.json. This fixes it for Node. You might be right in thinking that this means that the dev server isn't picking up the Babelized code, but I'm not positive -- you didn't post your Babel config. Can you double-check that there are no `import` statements in the output folder? e.g. `grep -R 'import' ./dist` – Codebling Jan 05 '22 at 21:17
  • @SethLutske I can take a look at your other question when I get a moment later – Codebling Jan 05 '22 at 21:17
  • I am using node v14.17.6. If I try to use any `import` or `export` statements in my code, I get `SyntaxError: Cannot use import statement outside a module`. If I add `"type": "module"` to the package.json, then I get `require is not defined in ES module scope, you can use import instead`, which tells me to use `type: commonjs` instead. But I need to slowly migrate an es5 codebase over to an es6 one. Changing all `require` and `exports.something` all at once would be too challenging. I was thinking I need babel to allow me to mix the two syntaxes. Also, babel config is in the package.json – Seth Lutske Jan 05 '22 at 22:09
  • @SethLutske I've edited the answer - one thing I missed in the `gulp-develop-server` example is that when it starts it is already set to load files from the compilation/transpilation directory – Codebling Jan 05 '22 at 22:46
  • @SethLutske were you able to get it to work? – Codebling Jan 10 '22 at 05:26
  • No, unfortunately not. I'm sort of giving up on this...modernizing this particular project is not a high priority, more of a nice-to-have, but the amount of time I've sunk into it so far just isn't worth it. I thought nodemon was a promising alternative, but as I explained in my other question (now also bountied), the lack of a proper stack trace makes development pretty much impossible. Oh well – Seth Lutske Jan 10 '22 at 05:28
  • @SethLutske yes, that sucks. Nodemon does seem like a better alternative. I took a look at the [other question](https://stackoverflow.com/questions/70521228/babel-and-node-no-stack-trace-on-syntax-errors), but I'm not able to reproduce. I left a comment and only now noticed that you responded (need to tag users otherwise they don't get a notification). I'll reply there, though I'm sure you've moved on anyhow. – Codebling Jan 10 '22 at 05:37
  • Actually I'm still holding out hope that I can go the nodemon route. If you have any other ideas about restoring proper stack tracing, that would be my ticket to modernizing this particular codebase. I'm all ears, thanks for your input – Seth Lutske Jan 10 '22 at 05:48
  • @SethLutske hope you saw the new answer in [your other question](https://stackoverflow.com/questions/70521228/babel-and-node-no-stack-trace-on-syntax-errors). I would still suggest avoiding Babel. There is a solution that works -- I've updated the answer. Use `.js` or `.cjs` when you want to use `require()`, and `.mjs` when you want to use `import`. Hope that helps! – Codebling Jan 10 '22 at 06:51