gulpfile.ts fails with any import statement

Viewed 1472

What were you expecting to happen? normal gulp operation when given a .ts file when ts-node is installed

What actually happened?

[10:24:59] Requiring external module ts-node/register
.\gulpfile.ts:3
import { __awaiter, __generator, __read, __spread } from "tslib";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Module._compile (internal/modules/cjs/loader.js:891:18)
...

if I tsc my gulpfile.ts, then gulp can process the transpiled output perfectly. Only if I directly give gulp the gulpfile.ts that it chokes. Flags my first statement (even if it is a comment) if my file contains any import statements.

I'm using import { src, dest, series, parallel } from 'gulp'; (see sample below) instead of const { src, dest, series, parallel } = require('gulp'); because require() is a typeless nodejs function (string) => any, losing all typing information. I can have all sorts of type errors in my gulpfile without being detected, defeating the purpose of writing it in TS.

With the import statements below, VSCode instanteously detects my error:

      src(srcFiles)
        .pipe<NodeJS.ReadWriteStream>(newer({dest: home, ext: '.js'}))
        .pipe<NodeJS.ReadWriteStream>(sourcemaps.init())
        .pipe<NodeJS.ReadWriteStream>(ts({
          lib: ['es2016', 'dom']
          , removeComments: true
        }))
        .pipe(uglify)
        .pipe<NodeJS.ReadWriteStream>(sourcemaps.write('.')) // sourcemap as separate file
        .pipe(dest(home))

but without typing, it took me a week to note where I went wrong.

Actually if I have changed all the require() statements to properly typed import statements, then I would not need to manually provide the type to pipe<T>() to have them properly type checked.

I have tried many different combinations of values to these tsconfig.json options:

  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "module": "esnext",
    "moduleResolution": "node",
  }

ts-node is installed locally. Package.json:

  "devDependencies": {
    "ts-node": "8.8.1",
    "tslib": "^1.11.1",
    "typescript": "^3.8.3"
  }

The only way out is to use gulp to transpile my gulpfile.ts into gulpfile.js and kick off a second gulp to process the output. But that sounds very complicated.

Please post a sample of your gulpfile (preferably reduced to just the bit that's not working) gulpfile.ts:

import { src, dest, series, parallel } from 'gulp';
import * as uglify from 'gulp-uglify';

What version of gulp are you using?

CLI version: 2.2.0
Local version: 4.0.2

What versions of npm and node are you using?

yarn -v
1.22.4

ts-node -v
ts-node v3.3.0
node v12.15.0
typescript v2.5.3

npm -v
6.7.0
1 Answers

I was getting a very similar error:

/project/gulpfile.ts:1
import gulp from 'gulp'; // or import * as gulp from 'gulp'
       ^^^^

SyntaxError: Unexpected identifier

The error occurs because gulp is incompatible with the module value of "esnext" in the tsconfig.json file. In some circumstances you can just change or remove this entry, but when using create-react-app, it will overwrite your edits on the next run.

You can get around this by specifying custom compiler options specifically for ts-node by adding a ts-node block to your tsconfig.json file like:

{
  "compilerOptions": {
    "module": "esnext"
  },
  "ts-node": {
    "compilerOptions": {
      "module": "commonjs"
    }
  }
}

With this change, you should be able to run your gulpfile.ts by just running gulp.

Related