Can compiler plugins use async functions?


#1

I’m writing a compiler plugin for mdx here:

The mdx compiler parses an mdx file and returns a promise that resolves to a string containing an es6 module. I’ve understood from this thread that I must include the babel compiler in my compiler to parse the js file that is returned by mdx. That part is fine, I still have not implemented it but it will probably work.

However, mdx returns a promise. When I do :

        const content = file.getContentsAsString().trim();
        const result = mdx(content); // result is a promise
        result.then(fileContent => {
          let data = fileContent
          file.addJavaScript({ // the files are not really added
            data,
            path,
          });
        });

I get Error: Cannot find module './docs.mdx' where docs.mdx is the file that i imported (my compiler creates a js file at docs.mdx.js)
So apparently I can’t wait for a promise to return and then call file.addJavascript
Anyone can help me? How can I run file.addJavascript in an async context?

Note: I’m not an async pro


#2

I think you need to return result.then(...) to make the build wait for the promise to resolve.


#3

Thanks! So because we are dealing with an array of files I did return Promise.all(.....)
I have a working solution :+1: the github has been updated if you want to have a look.

Since I have not implemented the cache I get the following warning: Compiling imports/docs.mdx with meteor-babel without a cache
From the other compilers that I saw, none was using the caching-compiler package. How do the coffeescript package or the ecmascript do it?
From the docs, I think my compiler should extends MultiFileCachingCompiler because one mdx file can import the compiled version of another ?


#4

Hi again! So i’ve got the compiler working now. I found out that mdx had a sync method so I stopped using the async one to make things easier for me.

I published a version (0.0.3) that uses the caching-compiler on atmosphere and github. I followed what is on the caching-compiler’s readme to set things up. There is something strange with it now: when I first launch the dev server with meteor I don’t have the warning message from meteor-babel : Compiling file.mdx with meteor-babel without a cache but it pops up when I update one of the mdx files and meteor recompiles.

I could really use a hand here, because I don’t know what I can do to have the cache working.

Thanks!


#5

You can implement the setDiskCacheDirectory method in your compiler class to get a cache directory and then use it as a cache option (third argument) for Babel.compile:

setDiskCacheDirectory(cacheDirectory) {
  this.cacheDirectory = cacheDirectory;
}
Babel.compile(code, options, {
  cacheDirectory: this.cacheDirectory
});

#6

Hi! Thanks for your reply. I’m not using Babel.compile, I’m using new BabelCompiler(...).processOneFileForTarget (which uses Babel.compile internally) I saw this on the coffeeScript compiler. Do you have any idea of how I could give the cacheDirectory option to this method?
I’ll try with Babel.compile anyway, and will inspire myself from svelte-meteor :star:


#7

Ok I made a lot of progress in a very short time thanks to @klaussner. new BabelCompiler(...) has its own setDiskCacheDirectory method. So I’ve added this method on my compiler, and I’m calling this.babelCompiler.setDiskCacheDirectory(this.cacheDirectory); to set Babel’s own cacheDirectory. I don’t think it’s a good idea to set the cache directory at each file but that’s the only place where I can think of putting it. The warning is gone now but I feel like the compiler takes more time now. I’ll try to use Profile to check this.


#8

Sounds like you’re on the right track now, but I would just add: make sure you’re not creating a new BabelCompiler object for every file. Instead, create it once in the constructor method of your plugin.


#9

I’m already creating the BabelCompiler only once in the constructor:

export default class MDXCompiler extends CachingCompiler {
  constructor() {
    super({
      compilerName: 'compile-mdx',
      defaultCacheSize: 1024 * 1024 * 10,
    });
    this.babelCompiler = new BabelCompiler({
      runtime: false, // keep this? it's from coffeeScript: https://github.com/meteor/meteor/blob/0fcc7ddd46d0ef8a278376ba64538210486ab646/packages/non-core/coffeescript-compiler/coffeescript-compiler.js#L25
      react: true,
    });
  }

I was wondering if it was right to set Babel’s cacheDirectory everytime in this.compileOneFile but I did not know where else to put it. And I found the answer: now I set Babel’s cacheDirectory in my own setCacheDirectory method. This way it only runs once and not at every compiled file:

  setDiskCacheDirectory(cacheDir) {
    this.cacheDirectory = cacheDir;
    this.babelCompiler.setDiskCacheDirectory(cacheDir);
  }

Next I would like to implement the possibility to add plugins to the mdx compiler. It would mean being able to import dynamically something inside the compiler. I really don’t know how to do this, because it would mean being able to set additional npm dependencies to the compiler, to be able to import it inside the compiler and pass it to mdx.sync(mdxText, { mdPlugins: [images, emoji] }).

@benjamn can you think of any way to achieve this kind of modularity?