Is it possible to compose compilers? #327

Closed
nikolaymatrosov opened this Issue Nov 11, 2015 · 6 comments

Projects

None yet

3 participants

@nikolaymatrosov

In my my latest project I have to use this loader chain babel?stage=0!ts-loader of webpack loaders to eliminate typescript compiler issues with import. I want to reproduce it in wallaby. As I understand, I need to make it work with wallby I need to remove loaders from webpack and use compilers instead. I found usages of Babel and TS compilers separately. Is there any way to combine them?
I know that I can transpile TypeScript directly to ES5, but I worry that it could cause inconsitency, that my test code could possibly work differntly from my other code.

@ArtemGovorov
Member

So you want to compile TS to ES6 with TS compiler and then transform ES6 to ES5 with babel, is it correct?

@ArtemGovorov
Member

If that's the case, then you may use Babel preprocessor + TypeScript compiler + webpack postprocessor like this:

var babel = require('babel');
var wallabyWebpack = require('wallaby-webpack');

var webpackPostprocessor = wallabyWebpack({});

module.exports = function (wallaby) {

  return {
    files: [
      { pattern: 'src/**/*.ts', load: false }
    ],

    tests: [
      { pattern: 'test/**/*Spec.ts', load: false }
    ],

    postprocessor: webpackPostprocessor,

    compilers: {
      '**/*.ts': wallaby.compilers.typeScript({
        module: 1,  // commonjs
        target: 2  // ES6
      })
    },

    preprocessors: {
      '**/*.js': file => babel.transform(file.content, {sourceMap: true})
    },

    bootstrap: function () {
      window.__moduleBundler.loadTests();
    }
  };
};

(you may need to slightly modify it if you are using babel 6 to add presets, etc.).

However, I'd recommend using direct compilation from TS to ES5, simply because it's faster than the double step one. You may run your tests on your CI server to catch any possible inconsistencies or have a separate wallaby config (with the double compilation) to run once in a while to catch possible inconsistencies.

Please let me know if it addresses your question.

@zemlanin
zemlanin commented Sep 2, 2016

With babel-core in preprocessors, source code is already modified in a way which can intervene with babel's transformations, like settings function names for arrow functions (example)

Yes, this particular case will be solved in Microsoft/TypeScript#6433, but who knows, maybe there are babel plugins that conflict with code coverage changes

@ArtemGovorov
Member

@zemlanin Thanks for the report. We'll see if we can do something about it. Do you have a real-world scenario where you're relying on the function names?

You're right that the issue will be fixed by the TypeScript related issue you've referenced. I also think babel plugin could do a better job of handling sequence expressions and transform

var TSX = (1,function (){});

to

var TSX = (1,function TSX(){});

and not to

var TSX = (1,function (){});

like it's doing now. I'll create an issue in babel issue tracker for that.

but who knows, maybe there are babel plugins that conflict with code coverage changes

It's true, no matter how small/smart code coverage changes are (or any code changes for that matter), some babel plugins may conflict with it. In fact, they may conflict with certain code structures that one has in the original source code and expects babel to process it in a certain way.

@zemlanin
zemlanin commented Sep 2, 2016

Do you have a real-world scenario where you're relying on the function names?

@ArtemGovorov Yes, testing with enzyme and its shallow render

const A = () => ...
const B = () => ...
const Wrapper = ({cond}) => <div>{cond ? <A /> : <B />}</div>

// fails without name
assert.equal(shallow(<Wrapper cond={true} />).text(), '<A />')
assert.equal(shallow(<Wrapper cond={false} />).text(), '<B />')
@ArtemGovorov
Member
ArtemGovorov commented Sep 2, 2016 edited

@zemlanin I have created the issue for babel: https://phabricator.babeljs.io/T7580, here is what you can use for now as a workaround:

module.exports = function (wallaby) {
  ...
  return {
    ...
    preprocessors: {
      '**/*.js*': (file) => require('babel-core').transform(file.content, {
        "presets": ["es2015", "react"],

        // hopefully this ends up in babel
        // https://github.com/babel/babel/blob/d81e154aca996780c8fd79ca6be7f3554d8b38a7/packages/babel-helper-function-name/src/index.js#L133
        plugins: [{
          visitor: {
            "ArrowFunctionExpression|FunctionExpression": {
              exit(path) {
                if (!path.node.id && path.parentPath && path.parentPath.isSequenceExpression()
                  && path.parentPath.parent && path.parent.expressions && path.parent.expressions.length
                  && path.parent.expressions[path.parent.expressions.length - 1] === path.node) {
                  path.node.id = path.parentPath.parent.id;
                }
              }
            }
          }
        }]
      })
    },
    ...
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment