javascript - Grunt och ES6-moduler i node - inkompatibla utan användning av .mjs?


Så, jag mixar lite med Typescript och Grunt för tillfället för att se om det är värt det för mig. Grejen är: Typescript kompilerar inte till *.mjs-filer utan bara vanliga *.js-filer. Node stöder ES6-moduler, men bara om du antingen markerar dem som *.jsm-filer eller genom att sätta "type": "module". Att sätta detta top-nivåfält i package.json har dock global räckvidd för alla *.js-filer i samma katalog och alla efterföljande.

Detta bryter Gruntfile.js-filen verkar det som eftersom den använder CommonJS-moduler, se min mycket grundläggande Gruntfile som exempel:

module.exports = function (grunt) {
   grunt.initConfig({
      ts: {
         default: {tsconfig: "./tsconfig.json"}
      }
   })
   grunt.loadNpmTasks("grunt-ts");
   grunt.registerTask("default", ["ts"]);
}

Utan att förvänta mig mycket framgång ändrade jag naivt exportsyntaxen från module.exports = till export default vilket som förväntat inte fungerade eftersom det inte hade mycket mening.

Frågor

  1. Finns det något alternativ att använda Grunt med ES6-moduler aktiverade i Node?
  2. Finns det ett korrekt sätt att säga till TypeScript att kompilera till *.mjs-filer?

Svar #1

Om du anger "type": "module" i din package.json måste du byta namn på Gruntfile.js till Gruntfile.cjs och köra det med grunt --gruntfile Gruntfile.cjs.

Svar #2

Den föreslagna metoden med Babel som körs före Grunt gör Grunt något överflödigt. Eftersom TypeScript ännu inte stödjer export av ES6-moduler till *.mjs-filer (och du måste använda *.mjs-suffixet i din import när node fortfarande ska köras med sitt CommonJS-system) och antagligen aldrig kommer att göra det fullt ut (se Design Meeting Notes 22/11/2019) måste jag dra slutsatsen att ES6-moduler fortfarande har allvarliga konsekvenser och problem. Att ändra filtillägget är inte tillräckligt eftersom import utan tillägg misslyckas med node. Du skulle behöva gå igenom varje kompilerad fil och ändra importen för att specifikt ladda *.mjs-filer.

Men TypeScript-kompilatorn kan ställas in på ett sätt så att den förstår ES6-modulsyntax och kan kompilera till CommonJS (se TS-handboken).

{
  "compilerOptions": {
    "module": "CommonJS",
    // [...]
  },
}

På detta sätt kan TypeScript-koden skrivas med ES6-modulsyntax och utdata kan vara kompatibel med CommonJS utan att bryta annan kod. Som en bonus kan du hoppa över Babel-metoden och grunt kan köra TS-kompilatorn.