kristerkari / react-native-sass-transformer

Use Sass to style your React Native apps.
MIT License
219 stars 19 forks source link

Feature: Possibility to give Sass options to Sass transformer #2

Closed kristerkari closed 5 years ago

kristerkari commented 6 years ago

I haven't yet found a way to easily pass custom options to metro bundler.

There is however a workaround that could be supported if nothing else works.

First we need to create a wrapper for transformers, and point rn-cli.config.js to point to it:

module.exports = {
  getTransformModulePath() {
    return require.resolve("./transformer.js");
  },
  getSourceExts() {
    return ["scss", "sass"];
  },
};

and then we create transformer.js and add our own Sass options to transformer's options:

var upstreamTransformer = require("metro/src/transformer");
var sassTransformer = require("react-native-sass-transformer");

module.exports.transform = function({ src, filename, options }) {
  if (filename.endsWith(".scss") || filename.endsWith(".sass")) {
    var opts = Object.assign(options, {
      sassOptions: {
        functions: {
          "rem($px)": px => {
            px.setValue(px.getValue() / 16);
            px.setUnit("rem");
            return px;
          },
        },
      },
    });
    return sassTransformer.transform({ src, filename, options: opts });
  } else {
    return upstreamTransformer.transform({ src, filename, options });
  }
};

After this we could simply check if options.sassOptions exists:

module.exports.transform = function(src, filename, options) {
  if (typeof src === "object") {
    // handle RN >= 0.46
    ({ src, filename, options } = src);
  }

  if (filename.endsWith(".scss") || filename.endsWith(".sass")) {
    var defaultOpts = {
      data: src
    };

    var opts = options.sassOptions
      ? Object.assign(options.sassOptions, defaultOpts)
      : defaultOpts;

    var result = sass.renderSync(opts);
    var css = result.css.toString();
    var cssObject = css2rn(css);

    return upstreamTransformer.transform({
      src: "module.exports = " + JSON.stringify(cssObject),
      filename,
      options
    });
  } else {
    return upstreamTransformer.transform({ src, filename, options });
  }
};

And the function can be used in CSS:

.element {
  padding: rem(20px);
}
kristerkari commented 5 years ago

Support for doing this added in v1.3.0